├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── ci.yaml │ └── release.yaml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── antora.yml └── modules │ └── ROOT │ ├── nav.adoc │ ├── pages │ ├── grgit-add.adoc │ ├── grgit-apply.adoc │ ├── grgit-authentication-2.adoc │ ├── grgit-authentication.adoc │ ├── grgit-branch.adoc │ ├── grgit-checkout.adoc │ ├── grgit-clean.adoc │ ├── grgit-clone.adoc │ ├── grgit-commit.adoc │ ├── grgit-describe.adoc │ ├── grgit-diff.adoc │ ├── grgit-fetch.adoc │ ├── grgit-gradle.adoc │ ├── grgit-head.adoc │ ├── grgit-init.adoc │ ├── grgit-isAncestorOf.adoc │ ├── grgit-log.adoc │ ├── grgit-lsremote.adoc │ ├── grgit-merge.adoc │ ├── grgit-open.adoc │ ├── grgit-pull.adoc │ ├── grgit-push.adoc │ ├── grgit-reference.adoc │ ├── grgit-remote.adoc │ ├── grgit-remove.adoc │ ├── grgit-reset.adoc │ ├── grgit-resolve.adoc │ ├── grgit-revert.adoc │ ├── grgit-show.adoc │ ├── grgit-status.adoc │ ├── grgit-tag.adoc │ └── index.adoc │ └── partials │ └── reference.adoc ├── gradle ├── eclipse-java-formatter.xml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── grgit-core ├── build.gradle.kts ├── gradle.lockfile └── src │ ├── main │ └── groovy │ │ └── org │ │ └── ajoberstar │ │ └── grgit │ │ ├── Branch.groovy │ │ ├── BranchStatus.groovy │ │ ├── Commit.groovy │ │ ├── CommitDiff.groovy │ │ ├── Credentials.groovy │ │ ├── DiffEntry.groovy │ │ ├── Grgit.groovy │ │ ├── Person.groovy │ │ ├── PushException.java │ │ ├── Ref.groovy │ │ ├── Remote.groovy │ │ ├── Repository.groovy │ │ ├── Status.groovy │ │ ├── Tag.groovy │ │ ├── auth │ │ ├── AuthConfig.groovy │ │ ├── GrgitSystemReader.java │ │ ├── TransportOpUtil.groovy │ │ └── package-info.groovy │ │ ├── operation │ │ ├── AddOp.groovy │ │ ├── ApplyOp.groovy │ │ ├── BranchAddOp.groovy │ │ ├── BranchChangeOp.groovy │ │ ├── BranchListOp.groovy │ │ ├── BranchRemoveOp.groovy │ │ ├── BranchStatusOp.groovy │ │ ├── CheckoutOp.groovy │ │ ├── CleanOp.groovy │ │ ├── CloneOp.groovy │ │ ├── CommitOp.groovy │ │ ├── DescribeOp.groovy │ │ ├── DiffOp.groovy │ │ ├── FetchOp.groovy │ │ ├── InitOp.groovy │ │ ├── LogOp.groovy │ │ ├── LsRemoteOp.groovy │ │ ├── MergeOp.groovy │ │ ├── OpenOp.groovy │ │ ├── PullOp.groovy │ │ ├── PushOp.groovy │ │ ├── RemoteAddOp.groovy │ │ ├── RemoteListOp.groovy │ │ ├── RemoteRemoveOp.groovy │ │ ├── ResetOp.groovy │ │ ├── RevertOp.groovy │ │ ├── RmOp.groovy │ │ ├── ShowOp.groovy │ │ ├── StatusOp.groovy │ │ ├── TagAddOp.groovy │ │ ├── TagListOp.groovy │ │ ├── TagRemoveOp.groovy │ │ └── package-info.groovy │ │ ├── package-info.groovy │ │ ├── service │ │ ├── BranchService.groovy │ │ ├── RemoteService.groovy │ │ ├── ResolveService.groovy │ │ ├── TagService.groovy │ │ └── package-info.groovy │ │ └── util │ │ ├── CoercionUtil.groovy │ │ ├── JGitUtil.groovy │ │ └── package-info.groovy │ ├── test │ ├── groovy │ │ └── org │ │ │ └── ajoberstar │ │ │ └── grgit │ │ │ ├── auth │ │ │ └── AuthConfigSpec.groovy │ │ │ ├── fixtures │ │ │ ├── Categories.groovy │ │ │ ├── GitTestUtil.groovy │ │ │ ├── MultiGitOpSpec.groovy │ │ │ └── SimpleGitOpSpec.groovy │ │ │ ├── operation │ │ │ ├── AddOpSpec.groovy │ │ │ ├── ApplyOpSpec.groovy │ │ │ ├── BranchAddOpSpec.groovy │ │ │ ├── BranchChangeOpSpec.groovy │ │ │ ├── BranchListOpSpec.groovy │ │ │ ├── BranchRemoveOpSpec.groovy │ │ │ ├── BranchStatusOpSpec.groovy │ │ │ ├── CheckoutOpSpec.groovy │ │ │ ├── CleanOpSpec.groovy │ │ │ ├── CloneOpSpec.groovy │ │ │ ├── CommitOpSpec.groovy │ │ │ ├── DescribeOpSpec.groovy │ │ │ ├── DiffOpSpec.groovy │ │ │ ├── FetchOpSpec.groovy │ │ │ ├── GenericOpTest.java │ │ │ ├── HeadSpec.groovy │ │ │ ├── InitOpSpec.groovy │ │ │ ├── LogOpSpec.groovy │ │ │ ├── LsRemoteOpSpec.groovy │ │ │ ├── MergeOpSpec.groovy │ │ │ ├── OpenOpSpec.groovy │ │ │ ├── PullOpSpec.groovy │ │ │ ├── PushOpSpec.groovy │ │ │ ├── RemoteAddOpSpec.groovy │ │ │ ├── RemoteListOpSpec.groovy │ │ │ ├── RemoveRemoveOpSpec.groovy │ │ │ ├── ResetOpSpec.groovy │ │ │ ├── RevertOpSpec.groovy │ │ │ ├── RmOpSpec.groovy │ │ │ ├── ShowOpSpec.groovy │ │ │ ├── StatusOpSpec.groovy │ │ │ ├── TagAddOpSpec.groovy │ │ │ ├── TagListOpSpec.groovy │ │ │ └── TagRemoveOpSpec.groovy │ │ │ └── util │ │ │ └── JGitUtilSpec.groovy │ └── resources │ │ └── org │ │ └── ajoberstar │ │ └── grgit │ │ └── operation │ │ └── sample.patch │ ├── transform1 │ └── groovy │ │ └── org │ │ └── ajoberstar │ │ └── grgit │ │ └── internal │ │ ├── AnnotateAtRuntime.java │ │ └── AnnotateAtRuntimeASTTransformation.java │ └── transform2 │ └── groovy │ └── org │ └── ajoberstar │ └── grgit │ ├── Configurable.groovy │ └── internal │ ├── OpSyntax.groovy │ ├── Operation.java │ ├── WithOperations.java │ └── WithOperationsASTTransformation.java ├── grgit-gradle ├── build.gradle.kts ├── gradle.lockfile ├── src │ ├── compatTest │ │ └── groovy │ │ │ └── org │ │ │ └── ajoberstar │ │ │ └── grgit │ │ │ └── gradle │ │ │ ├── GrgitPluginCompatTest.groovy │ │ │ ├── GrgitServiceCompatTest.groovy │ │ │ ├── GrgitServicePluginCompatTest.groovy │ │ │ └── GrgitServicePluginMultiProjectCompatTest.groovy │ └── main │ │ └── java │ │ └── org │ │ └── ajoberstar │ │ └── grgit │ │ └── gradle │ │ ├── GrgitPlugin.java │ │ ├── GrgitService.java │ │ ├── GrgitServiceExtension.java │ │ └── GrgitServicePlugin.java └── stutter.lockfile └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- 1 | # Ensure patch files are created with LF line endings 2 | *.patch text eol=lf 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | jobs: 7 | ci: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout repo 11 | uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 0 14 | 15 | - name: Setup Java 16 | uses: actions/setup-java@v4 17 | with: 18 | distribution: temurin 19 | java-version: | 20 | 11 21 | 17 22 | 21 23 | 24 | - name: Validate Gradle Wrapper 25 | uses: gradle/actions/wrapper-validation@v4 26 | - name: Setup Gradle 27 | uses: gradle/actions/setup-gradle@v4 28 | - name: Gradle build 29 | run: ./gradlew build --continue 30 | env: 31 | ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.PGP_SIGNING_KEY_ID }} 32 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.PGP_SIGNING_KEY }} 33 | ORG_GRADLE_PROJECT_signingPassphrase: ${{ secrets.PGP_SIGNING_PASSPHRASE }} 34 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: ["*"] 5 | jobs: 6 | release: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout repo 10 | uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 0 13 | - name: Setup Java 14 | uses: actions/setup-java@v4 15 | with: 16 | distribution: temurin 17 | java-version: | 18 | 11 19 | 17 20 | 21 21 | 22 | - name: Validate Gradle Wrapper 23 | uses: gradle/actions/wrapper-validation@v4 24 | - name: Setup Gradle 25 | uses: gradle/actions/setup-gradle@v4 26 | - name: Gradle publish 27 | env: 28 | BUNDLE_REPO: .bundle 29 | ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.PGP_SIGNING_KEY_ID }} 30 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.PGP_SIGNING_KEY }} 31 | ORG_GRADLE_PROJECT_signingPassphrase: ${{ secrets.PGP_SIGNING_PASSPHRASE }} 32 | GRADLE_OPTS: "-Dorg.gradle.project.gradle.publish.key=${{ secrets.GRADLE_PLUGIN_KEY }} -Dorg.gradle.project.gradle.publish.secret=${{ secrets.GRADLE_PLUGIN_SECRET }}" 33 | run: ./gradlew publishAllPublicationsToCentralRepository --stacktrace 34 | - name: Create bundle 35 | run: | 36 | cd .bundle 37 | zip -r ../bundle.zip * 38 | - name: Publish to Maven Central 39 | uses: ajoberstar/maven-central-publish@main 40 | with: 41 | username: ${{ secrets.CENTRAL_USERNAME }} 42 | token: ${{ secrets.CENTRAL_TOKEN }} 43 | bundle-path: bundle.zip 44 | name: ${{ github.repository }}@${{ github.ref }} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | .settings 4 | .project 5 | .classpath 6 | bin 7 | *~ 8 | *.iml 9 | *.iws 10 | *.ipr 11 | .idea 12 | out 13 | *.sublime-* 14 | *.swp 15 | -------------------------------------------------------------------------------- /docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: grgit 2 | version: true 3 | nav: 4 | - modules/ROOT/nav.adoc 5 | -------------------------------------------------------------------------------- /docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | include::partial$reference.adoc[] 2 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-add.adoc: -------------------------------------------------------------------------------- 1 | = grgit-add 2 | 3 | == Name 4 | 5 | grgit-add - Add file contents to the index 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.add(patterns: ['', ...], update: ) 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.add { 17 | patterns = ['', ...] 18 | update = 19 | } 20 | ---- 21 | 22 | == Description 23 | 24 | This command updates the index using the current content found in the working tree, to prepare the content staged for the next commit. It typically adds the current content of existing paths as a whole, but with some options it can also be used to remove paths that do not exist in the working tree anymore. 25 | 26 | The "index" holds a snapshot of the content of the working tree, and it is this snapshot that is taken as the contents of the next commit. Thus after making any changes to the working tree, and before running the commit command, you must use the add command to add any new or modified files to the index. 27 | 28 | This command can be performed multiple times before a commit. It only adds the content of the specified file(s) at the time the add command is run; if you want subsequent changes included in the next commit, then you must run `add` again to add the new content to the index. 29 | 30 | The xref:grgit-status.adoc[grgit-status] command can be used to obtain a summary of which files have changes that are staged for the next commit. 31 | 32 | Please see xref:grgit-commit.adoc[grgit-commit] for alternative ways to add content to a commit. 33 | 34 | == Options 35 | 36 | patterns:: (`Set`, default `[]`) Files to add content from. A leading directory name (e.g. `dir` to add `dir/file1` and `dir/file2`) can be given to update the index to match the current state of the directory as a whole (e.g. specifying `dir` will record not just a file `dir/file1` modified in the working tree, a file `dir/file2` added to the working tree, but also a file `dir/file3` removed from the working tree. 37 | update:: (`boolean`, default `false`) Update the index just where it already has an entry matching `patterns`. This removes as well as modifies index entries to match the working tree, but adds no new files. 38 | + 39 | If no `pathspec` is given when `update` option is used, all tracked files in the entire working tree are updated. 40 | 41 | == Examples 42 | 43 | To add specific files or directories to the path. Wildcards are not supported. 44 | 45 | [source, groovy] 46 | ---- 47 | grgit.add(patterns: ['1.txt', 'some/dir']) 48 | ---- 49 | 50 | To add changes to all currently tracked files. 51 | 52 | [source, groovy] 53 | ---- 54 | grgit.add(update: true) 55 | ---- 56 | 57 | == See Also 58 | 59 | - link:https://git-scm.com/docs/git-add[git-add] 60 | - xref:grgit-remove.adoc[grgit-remove] 61 | - xref:grgit-commit.adoc[grgit-commit] 62 | - xref:grgit-status.adoc[grgit-status] 63 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-apply.adoc: -------------------------------------------------------------------------------- 1 | = grgit-apply 2 | 3 | == Name 4 | 5 | grgit-apply - Apply a patch to files. 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.apply(patch: 18 | } 19 | ---- 20 | 21 | == Description 22 | 23 | Reads the supplied diff output (i.e. "a patch") and applies it to files in the repository. 24 | 25 | This command applies the patch but does not create a commit. 26 | 27 | == Options 28 | 29 | patch:: (`Object`, default: `null`) The file to read the patch from. This can be a `java.io.File`, `java.nio.file.Path`, or a `String`. 30 | 31 | == Examples 32 | 33 | [source, groovy] 34 | ---- 35 | grgit.apply(patch: '/some/file.patch') 36 | ---- 37 | 38 | == See Also 39 | 40 | - link:https://git-scm.com/docs/git-apply[git-apply] 41 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-authentication.adoc: -------------------------------------------------------------------------------- 1 | = grgit-authentication 2 | 3 | == Description 4 | 5 | [IMPORTANT] 6 | ==== 7 | JSCH authentication (and its agent proxy) are not supported in Grgit 3.x. 8 | 9 | If you're using Grgit 2.x, see the xref:grgit-authentication-2.adoc[documentation] for that version. 10 | ==== 11 | 12 | Grgit communicates with remote repositories in one of three ways: 13 | 14 | . HTTP(S) protocol with basic auth credentials (i.e. username/password). 15 | + 16 | TIP: Where possible, use of HTTPS urls is preferred over the SSH options. It has far simpler behavior than the SSH options. 17 | . SSH protocol using `ssh` or `plink` directly. This approach should work as long as you can push/pull on your machine. 18 | + 19 | TIP: You should be using an SSH agent to have your key loaded before Grgit runs. 20 | 21 | == HTTP BasicAuth Credentials 22 | 23 | These are presented in precedence order (direct parameter in code, system properties, environment variables). 24 | 25 | === Parameter to Grgit operations 26 | 27 | Some Grgit operations, such as xref:grgit-clone.adoc[grgit-clone] allow you to provide credentials programmatically. 28 | 29 | [source, groovy] 30 | ---- 31 | import org.ajoberstar.grgit.Grgit 32 | import org.ajoberstar.grgit.Credentials 33 | 34 | def grgit = Grgit.clone(dir: '...', url: '...', credentials: new Credentials(username, password)) 35 | ---- 36 | 37 | === System Properties 38 | 39 | org.ajoberstar.grgit.auth.username:: Username to provide when basic authentication credentials are needed. Username can be specified without a password (e.g. using a GitHub auth token as the user and providing no password). 40 | org.ajoberstar.grgit.auth.password:: Password to provide when basic authentication credentials are needed. 41 | 42 | === Environment Variables 43 | 44 | GRGIT_USER:: Username to provide when basic authentication credentials are needed. Username can be specified without a password (e.g. using a GitHub auth token as the user and providing no password). 45 | GRGIT_PASS:: Password to provide when basic authentication credentials are needed. 46 | 47 | == SSH 48 | 49 | If the `GIT_SSH` environment variable is set, that command will be used. If not, Grgit will scan your `PATH` for an `ssh` (preferred) or `plink` command. 50 | 51 | Any keys your `ssh` or `plink` can natively pick up will be used. This should include keys in default locations (e.g. `~/`) and any compatible SSH agent or OS keychain. 52 | 53 | [CAUTION] 54 | ==== 55 | Grgit cannot provide credentials to the system `ssh` or `plink` commands. If your key is password protected and not loaded in an agent, authentication _will_ fail **or** hang indefinitely. 56 | ==== 57 | 58 | == Examples 59 | 60 | This is a non-exhaustive list of examples of how to configure authentication in common scenarios. 61 | 62 | === Using a GitHub auth token with HTTPS URLs 63 | 64 | Set the environment variable `GRGIT_USER` to your authentication token from GitHub. 65 | 66 | === Using a Username and Password with HTTPS URLs 67 | 68 | Set the system properties: 69 | 70 | ---- 71 | groovy -Dorg.ajoberstar.grgit.auth.username=someone -Dorg.ajoberstar.grgit.auth.password=mysecretpassword myscript.groovy 72 | ---- 73 | 74 | === Using ssh-agent 75 | 76 | Make sure your ssh-agent is started and your key is loaded. Then just run your application or script. 77 | 78 | === Using Pageant 79 | 80 | Make sure your Pageant is started and your key is loaded. Then just run your application or script. 81 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-clean.adoc: -------------------------------------------------------------------------------- 1 | = grgit-clean 2 | 3 | == Name 4 | 5 | grgit-clean - Remove untracked files from the working tree 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.clean() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.clean(paths: ['', ...], directories: , dryRun: , ignore: ) 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.clean { 22 | paths = ['', ...] 23 | directories = 24 | dryRun = 25 | ignore = 26 | } 27 | ---- 28 | 29 | == Description 30 | 31 | Cleans the working tree by removing files that are not under version control. 32 | 33 | Normally, only files uknown to Git are removed, but if `ignore` is `false`, ignored files are also removed. This can, for example, be useful to remove all build products. 34 | 35 | If any optional `paths` are given, only those paths are affected. 36 | 37 | Returns a `Set` of the paths that were deleted. 38 | 39 | == Options 40 | 41 | directories:: (`boolean`, default `false`) Remove untracked directories in addition to untracked files. 42 | dryRun:: (`boolean`, default `false`) Don’t actually remove anything, just show what would be done. 43 | ignore:: (`boolean`, default `true`) Don’t use the standard ignore rules read from .gitignore (per directory) and $GIT_DIR/info/exclude. This allows removing all untracked files, including build products. This can be used (possibly in conjunction with git reset) to create a pristine working directory to test a clean build. 44 | paths:: (`Set`, default `null`) Only remove files in the given paths. 45 | 46 | == Examples 47 | 48 | To clean all untracked files, but not ignored ones or untracked directories. 49 | 50 | [source, groovy] 51 | ---- 52 | def cleanedPaths = grgit.clean() 53 | ---- 54 | 55 | To clean all untracked files and directories. 56 | 57 | [source, groovy] 58 | ---- 59 | def cleanedPaths = grgit.clean(directories: true) 60 | ---- 61 | 62 | To clean all untracked files, including ignored ones. 63 | 64 | [source, groovy] 65 | ---- 66 | def cleanedPaths = grgit.clean(ignore: false) 67 | ---- 68 | 69 | To only return files that would be cleaned. 70 | 71 | [source, groovy] 72 | ---- 73 | def cleanedPaths = grgit.clean(dryRun: true) 74 | ---- 75 | 76 | To clean specific untracked files. 77 | 78 | [source, groovy] 79 | ---- 80 | def cleanedPaths = grgit.clean(paths: ['specific/file.txt']) 81 | ---- 82 | 83 | == See Also 84 | 85 | - link:https://git-scm.com/docs/git-clean[git-clean] 86 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-clone.adoc: -------------------------------------------------------------------------------- 1 | = grgit-clone 2 | 3 | == Name 4 | 5 | grgit-clone - Clone a repository into a new directory 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | Grgit.clone(dir: , uri: , remote: , all: , 12 | bare: , branches: , checkout: , 13 | refToCheckout: , depth: , credentials: ) 14 | ---- 15 | 16 | [source, groovy] 17 | ---- 18 | Grgit.clone { 19 | dir = 20 | uri = 21 | remote = 22 | all = 23 | bare = 24 | branches = 25 | checkout = 26 | refToCheckout = 27 | depth = 28 | credentials = 29 | } 30 | ---- 31 | 32 | == Description 33 | 34 | Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository, and creates and checks out an initial branch that is forked from the cloned repository’s currently active branch. 35 | 36 | After the clone, a plain xref:grgit-fetch.adoc[grgit-fetch] without arguments will update all the remote-tracking branches, and a xref:grgit-pull.adoc[grgit-pull] without arguments will in addition merge the remote master branch into the current master branch. 37 | 38 | This default configuration is achieved by creating references to the remote branch heads under `refs/remotes/origin` and by initializing `remote.origin.url` and `remote.origin.fetch` configuration variables. 39 | 40 | Returns a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Grgit.groovy[Grgit] instance. 41 | 42 | == Options 43 | 44 | dir:: (`Object`, default `null`) The directory the repository should be cloned into. Can be a `File`, `Path`, or `String`. 45 | uri:: (`String`, default `null`) The URI to the repository to be cloned. 46 | remote:: (`String`, default `origin`) Instead of using the remote name `origin` to keep track of the upstream repository, use ``. 47 | all:: (`boolean`, default `false`) Clone all branches. 48 | bare:: (`boolean`, default `false`) Create a bare repository. 49 | branches:: (`List`, `[]`) Select full refs to use with `all = false`. 50 | checkout:: (`boolean`, default `true`) Set to `false` to skip checking out a `HEAD`. 51 | refToCheckout:: (`String`, default `null`) Instead of pointing the newly created `HEAD` to the branch pointed to by the cloned repository’s `HEAD`, point to `` branch instead. In a non-bare repository, this is the branch that will be checked out. This can also take tags and detaches the `HEAD` at that commit in the resulting repository. 52 | depth:: (`Integer`, default `null`) If set, does a shallow clone to the specified depth 53 | credentials:: (`Credentials`, default `null`) An instance of link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Credentials.groovy[Credentials] containing username/password to be used in operations that require authentication. See xref:grgit-authentication.adoc[grgit-authentication] for preferred ways to configure this. 54 | 55 | == Examples 56 | 57 | == See Also 58 | 59 | - link:https://git-scm.com/docs/git-clone[git-clone] 60 | - xref:grgit-init.adoc[grgit-init] 61 | - xref:grgit-open.adoc[grgit-open] 62 | - xref:grgit-authentication.adoc[grgit-authentication] 63 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-diff.adoc: -------------------------------------------------------------------------------- 1 | = grgit-diff 2 | 3 | == Name 4 | 5 | grgit-diff - Show changed files between commits 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.diff() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.diff(oldCommit: , newCommit: , pathFilter: ) 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.diff { 22 | oldCcommit = 23 | newCommit = 24 | pathFilter = 25 | } 26 | ---- 27 | 28 | == Description 29 | 30 | Show changed files between commits. 31 | 32 | Returns a `List` link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/DiffEntry.groovy[DiffEntry] that matches pathFilter or all. 33 | 34 | == Options 35 | 36 | oldCommit:: (`Object`, default: `HEAD`) A revstring-ish object naming the commit. For a more complete list of ways to specify a revstring, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toRevisionString` method). 37 | 38 | newCommit:: (`Object`, default: `HEAD`) A revstring-ish object naming the commit. For a more complete list of ways to specify a revstring, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toRevisionString` method). 39 | 40 | pathFilter:: (`String`, default: `null`) Limit the output to only files matching pathFilter. If omitted all files are returned. 41 | 42 | == Examples 43 | 44 | To get a list of changes between a commit and HEAD 45 | 46 | [source, groovy] 47 | ---- 48 | List l = grgit.diff(oldCommit: 'b920cb5a16b8020568b77019e9abc77683037271') 49 | ---- 50 | 51 | To get a list of changes for files with file path starting with foo/bar between a commit and HEAD 52 | 53 | [source, groovy] 54 | ---- 55 | List l = grgit.diff(oldCommit: 'b920cb5a16b8020568b77019e9abc77683037271', pathFilter: 'foo/bar') 56 | ---- 57 | 58 | To get a list of changes between a tag and HEAD 59 | 60 | [source, groovy] 61 | ---- 62 | List l = grgit.diff(oldCommit: 'Foo_release') 63 | ---- 64 | 65 | To get a list of changes between two tags 66 | 67 | [source, groovy] 68 | ---- 69 | List l = grgit.diff(oldCommit: 'Foo_1.0_release', newCommit: 'Foo_2.0_release') 70 | ---- 71 | 72 | == See Also 73 | 74 | - link:https://git-scm.com/docs/git-diff[git-diff] 75 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-fetch.adoc: -------------------------------------------------------------------------------- 1 | = grgit-fetch 2 | 3 | == Name 4 | 5 | grgit-fetch - Download objects and refs from another repository 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.fetch() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.fetch(remote: '', refSpecs: [, ...], prune: , depth: , tagMode: ) 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.fetch { 22 | remote = '' 23 | refspecs = [, ...] 24 | prune = 25 | depth = 26 | tagMode = 27 | } 28 | ---- 29 | 30 | == Description 31 | 32 | Fetch branches and/or tags (collectively, "refs") from one or more other repositories, along with the objects necessary to complete their histories. Remote-tracking branches are updated (see the description of below for ways to control this behavior). 33 | 34 | By default, any tag that points into the histories being fetched is also fetched; the effect is to fetch tags that point at branches that you are interested in. This default behavior can be changed by using a `tagMode` of `'all'` or `'none'' or by configuring `remote..tagOpt`. By using a refspec that fetches tags explicitly, you can fetch tags that do not point into branches you are interested in as well. 35 | 36 | When no remote is specified, by default the origin remote will be used, unless there’s an upstream branch configured for the current branch. 37 | 38 | == Options 39 | 40 | remote:: (`String`, default `null`) The "remote" repository that is source of a fetch operation. This parameter can be either a URL or the name of a remote. 41 | refspecs:: (`List`, default `[]`) Specifies which refs to fetch and which local refs to update. When no s are provided, the refs to fetch are read from `remote..fetch` variables instead. 42 | + 43 | The format of a parameter is an optional plus +, followed by the source ref , followed by a colon :, followed by the destination ref . The colon can be omitted when is empty. 44 | + 45 | The remote ref that matches is fetched, and if is not empty string, the local ref that matches it is fast-forwarded using . If the optional plus + is used, the local ref is updated even if it does not result in a fast-forward update. 46 | prune:: (`boolean`, default `false`) Before fetching, remove any remote-tracking references that no longer exist on the remote. Tags are not subject to pruning if they are fetched only because of the default tag auto-following or due to a `tagMode` option. However, if tags are fetched due to an explicit refspec, then they are also subject to pruning. 47 | depth: (`Integer`, default `null`) If set, limits fetching to the specified number of commits from the tip each remote branch history 48 | tagMode:: (`String`, default `auto`) Must be one of `'auto'`, `'all'`, `'none'`. 49 | + 50 | `'auto'` - tags that point at objects that are downloaded from the remote repository are fetched and stored locally. 51 | + 52 | `'none'` - disables automatic tag following. 53 | + 54 | `'all'` - Fetch all tags from the remote (i.e., fetch remote tags `refs/tags/*` into local tags with the same name), in addition to whatever else would otherwise be fetched. 55 | 56 | == Examples 57 | 58 | == See Also 59 | 60 | - link:https://git-scm.com/docs/git-fetch[git-fetch] 61 | - xref:grgit-pull.adoc[grgit-pull] 62 | - xref:grgit-push.adoc[grgit-push] 63 | - xref:grgit-authentication.adoc[grgit-authentication] 64 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-gradle.adoc: -------------------------------------------------------------------------------- 1 | = grgit-gradle 2 | 3 | ## Applying the Plugin 4 | 5 | Get the available versions from the link:https://github.com/ajoberstar/grgit/releases[releases] page. Generally, you should only apply the plugin to the root project of your build. 6 | 7 | ```groovy 8 | plugins { 9 | id 'org.ajoberstar.grgit' version '' 10 | } 11 | ``` 12 | 13 | ## What does the plugin do? 14 | 15 | The `org.ajoberstar.grgit` plugin adds a `grgit` property to your build, which is an instance of link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Grgit.groovy[Grgit] opened to the repository visible from your project's root dir. This will check the project directory and its parents for a `.git` directory. If no repository is found, the `grgit` property is `null`. 16 | 17 | ```groovy 18 | version = "1.0.0-${grgit.head().abbreviatedId}" 19 | 20 | task tagRelease { 21 | description = 'Tags the current head with the project\'s version.' 22 | doLast { 23 | grgit.tag.add { 24 | name = version 25 | message = "Release of ${version}" 26 | } 27 | } 28 | } 29 | 30 | task pushToOrigin { 31 | description = 'Pushes current branch\'s committed changes to origin repo.' 32 | doLast { 33 | grgit.push() 34 | } 35 | } 36 | ``` 37 | 38 | For details on the available operations, see the xref:grgit-reference.adoc[reference]. Examples are provided there. 39 | 40 | ## Just getting the library 41 | 42 | If you don't want to interact with the project's repository, but still want to use Grgit. 43 | 44 | ```groovy 45 | plugins { 46 | id 'org.ajoberstar.grgit' version '' apply false 47 | } 48 | ``` 49 | 50 | Then you can import Grgit and continue from there: 51 | 52 | ```groovy 53 | import org.ajoberstar.grgit.Grgit 54 | 55 | task cloneSomeRepo { 56 | doLast { 57 | def grgit = Grgit.clone(dir: "$buildDir/my-repo", uri: "https://github.com/ajoberstar/grgit.git") 58 | println grgit.describe() 59 | } 60 | } 61 | ``` 62 | 63 | ## Authentication 64 | 65 | If you will be doing a clone, fetch, push, or pull, review the xref:grgit-authentication.adoc[grgit-authentication] page for details on how to configure credentials for these commands. 66 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-head.adoc: -------------------------------------------------------------------------------- 1 | = grgit-head 2 | 3 | == Name 4 | 5 | grgit-head - Gets the current `HEAD` commit. 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.head() 12 | ---- 13 | 14 | == Description 15 | 16 | Returns the link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy[Commit] that the current `HEAD` points to. 17 | 18 | == Options 19 | 20 | == Examples 21 | 22 | == See Also 23 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-init.adoc: -------------------------------------------------------------------------------- 1 | = grgit-init 2 | 3 | == Name 4 | 5 | grgit-init - Create an empty Git repository 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | Grgit.init(dir: , bare: ) 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | Grgit.init { 17 | dir = 18 | bare = 19 | } 20 | ---- 21 | 22 | == Description 23 | 24 | This command creates an empty Git repository - basically a `.git` directory with subdirectories for `objects`, `refs/heads`, `refs/tags`, and template files. An initial `HEAD` file that references the HEAD of the master branch is also created. 25 | 26 | Returns a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Grgit.groovy[Grgit] instance. 27 | 28 | == Options 29 | 30 | dir:: (`Object`, default `null`) The directory the repository should be initialized in. Can be a `File`, `Path`, or `String`. 31 | bare:: (`boolean`, default `false`) Create a bare repository. 32 | 33 | == Examples 34 | 35 | == See Also 36 | 37 | - link:https://git-scm.com/docs/git-init[git-init] 38 | - xref:grgit-open.adoc[grgit-open] 39 | - xref:grgit-clone.adoc[grgit-clone] 40 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-isAncestorOf.adoc: -------------------------------------------------------------------------------- 1 | = grgit-isAncestorOf 2 | 3 | == Name 4 | 5 | grgit-isAncestorOf - Tell if a commit is an ancestor of another. 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.isAncestorOf(, ) 12 | ---- 13 | 14 | == Description 15 | 16 | Given a base commit and a tip commit, return `true` if the base commit can be reached by walking back from the tip. 17 | 18 | == Options 19 | 20 | . (`Object`) base commit. For a more complete list of objects you can pass in, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toCommit` method). 21 | . (`Object`) tip commit. For a more complete list of objects you can pass in, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toCommit` method). 22 | 23 | == Examples 24 | 25 | [source, groovy] 26 | ---- 27 | grgit.isAncestorOf('v1.2.3', 'master') 28 | ---- 29 | 30 | == See Also 31 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-log.adoc: -------------------------------------------------------------------------------- 1 | = grgit-log 2 | 3 | == Name 4 | 5 | grgit-log - Show commit logs 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.log() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.log(includes: [, ...], excludes: [, ...], paths: [, ...], 17 | skipCommits: , maxCommits: ) 18 | ---- 19 | 20 | [source, groovy] 21 | ---- 22 | grgit.log { 23 | includes = [, ...] 24 | excludes = [, ...] 25 | paths = [, ...] 26 | skipCommits = 27 | maxCommits = 28 | range(, ) 29 | } 30 | ---- 31 | 32 | == Description 33 | 34 | Shows the commit logs. 35 | 36 | List commits that are reachable by following the parent links from the given `includes` commit(s), but exclude commits that are reachable from the one(s) given with the `excludes` option. The output is given in reverse chronological order. 37 | 38 | You can think of this as a set operation. Commits given in `includes` form a set of commits that are reachable from any of them, and then commits reachable from any of the ones given with `excludes` are subtracted from that set. The remaining commits are what comes out in the result. Various other options and paths parameters can be used to further limit the result. 39 | 40 | Thus, the following command means "list all the commits which are reachable from foo or bar, but not from baz". 41 | 42 | [source, groovy] 43 | ---- 44 | grgit.log(includes: ['foo', 'bar'], excludes: ['baz']) 45 | ---- 46 | 47 | A special notation (in the Closure syntax only) `range(, )` can be used as a short-hand for `excludes: [], includes: []`. For example, either of the following may be used interchangeably: 48 | 49 | [source, groovy] 50 | ---- 51 | grgit.log(includes: ['HEAD'], excludes: ['origin/master']) 52 | grgit.log { 53 | range('origin/master', 'HEAD') 54 | } 55 | ---- 56 | 57 | Returns a `List` (link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy[Commit]) with the commits matching the criteria given. 58 | 59 | == Options 60 | 61 | includes:: (`List`, default `[]`) Commit-ish object names to include the history of in the output. For a more complete list of ways to spell commit names, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toCommit` method). 62 | excludes:: (`List`, default `[]`) Commit-ish object names to exclude the history of in the output. For a more complete list of ways to spell commit names, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toCommit` method). 63 | skipCommits:: (`int`, default `-1`) Skip `skipCommits` commits before starting to show the commit output. A negative value ignores this option. 64 | maxCommits:: (`int`, default `-1`) Limit the number of commits to output. A negative value ignores this option. 65 | paths:: (`List`, defaul: `[]`) Commits modifying the given paths are selected. Omitting this will include all reachable commits. 66 | 67 | == Examples 68 | 69 | == See Also 70 | 71 | - link:https://git-scm.com/docs/git-log[git-log] 72 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-lsremote.adoc: -------------------------------------------------------------------------------- 1 | = grgit-lsremote 2 | 3 | == Name 4 | 5 | grgit-lsremote - List references in a remote repository 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.lsremote() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.lsremote(heads: , tags: , remote: '') 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.lsremote { 22 | heads = 23 | tags = 24 | remote = '' 25 | } 26 | ---- 27 | 28 | == Description 29 | 30 | Returns a `Map` (link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Ref.groovy[Ref]) containing references available in the remote, and the object ID they currently point to. 31 | 32 | == Options 33 | 34 | heads:: (`boolean`, default `false`) Limit to `refs/heads`. This is not mutually exclusive with `tags`; when given both, references stored in both places are returned. 35 | tags:: (`boolean`, default `false`) Limit to `refs/tags`. This is not mutually exclusive with `heads`; when given both, references stored in both places are returned. 36 | remote:: (`String`, default `'origin'`) The name of the remote or the URI of the repository to list. 37 | 38 | == Examples 39 | 40 | [source, groovy] 41 | .Code 42 | ---- 43 | grgit.lsremote(tags: true).each { ref, id -> 44 | println "${id} ${ref.fullName}" 45 | } 46 | ---- 47 | 48 | .Output 49 | ---- 50 | d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99 51 | f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1 52 | 7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3 53 | c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2 54 | ---- 55 | 56 | == See Also 57 | 58 | - link:https://git-scm.com/docs/git-ls-remote[git-ls-remote] 59 | - xref:grgit-remote.adoc[grgit-remote] 60 | - xref:grgit-authentication.adoc[grgit-authentication] 61 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-merge.adoc: -------------------------------------------------------------------------------- 1 | = grgit-merge 2 | 3 | == Name 4 | 5 | grgit-merge - Join two or more development histories together 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.merge(head: , mode: , message: ) 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.merge { 17 | head = 18 | mode = 19 | message = 20 | } 21 | ---- 22 | 23 | == Description 24 | 25 | Incorporates changes from the named commits (since the time their histories diverged from the current branch) into the current branch. This command is used by xref:grgit-pull.adoc[grgit-pull] to incorporate changes from another repository and can be used by hand to merge changes from one branch into another. 26 | 27 | Assume the following history exists and the current branch is "master": 28 | 29 | ---- 30 | A---B---C topic 31 | / 32 | D---E---F---G master 33 | ---- 34 | 35 | Then `grgit.merge(head: 'topic')` will replay the changes made on the topic branch since it diverged from master (i.e., `E`) until its current commit `C` on top of master, and record the result in a new commit along with the names of the two parent commits and a log message from the user describing the changes. 36 | 37 | ---- 38 | A---B---C topic 39 | / \ 40 | D---E---F---G---H master 41 | ---- 42 | 43 | This is a simplified version of merge. If any conflict occurs the merge will throw an exception. The conflicting files can be identified with xref:grgit-status.adoc[grgit-status]. 44 | 45 | == Options 46 | 47 | head:: (`Object`, default `null`) Commit, usually another branch head, to merge into our branch. For a more complete list of acceptable inputs, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toRevisionString` method). 48 | mode:: (`String`, default `default`) Must be one of `default`, `only-ff`, `create-commit`, `squash`, `no-commit`. 49 | `default`:::: When the merge resolves as a fast-forward, only update the branch pointer, without creating a merge commit. 50 | `only-ff`:::: Refuse to merge and fail with an exception unless the current `HEAD` is already up-to-date or the merge can be resolved as a fast-forward. 51 | `create-commit`:::: Create a merge commit even when the merge resolves as a fast-forward. 52 | `squash`:::: Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit, move the `HEAD`, or record `$GIT_DIR/MERGE_HEAD` (to cause the next git commit command to create a merge commit). This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus). 53 | `no-commit`:::: Perform the merge but pretend the merge failed and do not autocommit, to give the user a chance to inspect and further tweak the merge result before committing. 54 | message:: (`String`, default `null`) Use the given as the merge commit message. 55 | 56 | == Examples 57 | 58 | == See Also 59 | 60 | - link:https://git-scm.com/docs/git-merge[git-merge] 61 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-open.adoc: -------------------------------------------------------------------------------- 1 | = grgit-open 2 | 3 | == Name 4 | 5 | grgit-open - Open an existing Git repository 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | Grgit.open() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | Grgit.open(dir: , currentDir: , credentials: ) 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | Grgit.open { 22 | dir = 23 | currentDir = 24 | credentials = 25 | } 26 | ---- 27 | 28 | == Description 29 | 30 | This command opens an existing Git repository. If both `dir` and `currentDir` are `null`, acts as if the `currentDir` is the JVM's working directory. 31 | 32 | Returns a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Grgit.groovy[Grgit] instance. 33 | 34 | == Options 35 | 36 | dir:: (`Object`, default `null`) The directory the repository is in. Can be a `File`, `Path`, or `String`. 37 | currentDir:: (`Object`, default `null`) The directory to start searching for the repository from. Can be a `File`, `Path`, or `String`. 38 | credentials:: (`Credentials`, default `null`) An instance of link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Credentials.groovy[Credentials] containing username/password to be used in operations that require authentication. See xref:grgit-authentication.adoc[grgit-authentication] for preferred ways to configure this. 39 | 40 | == Examples 41 | 42 | == See Also 43 | 44 | - xref:grgit-init.adoc[grgit-init] 45 | - xref:grgit-clone.adoc[grgit-clone] 46 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-pull.adoc: -------------------------------------------------------------------------------- 1 | = grgit-pull 2 | 3 | == Name 4 | 5 | grgit-pull - Fetch from and integrate with another repository or a local branch 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.pull() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.pull(remote: '', branch: '', rebase: ) 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.pull { 22 | remote = '' 23 | branch = '' 24 | rebase = 25 | } 26 | ---- 27 | 28 | == Description 29 | 30 | Incorporates changes from a remote repository into the current branch. In its default mode, git pull is shorthand for fetch followed by merge. 31 | 32 | More precisely, pull runs fetch with the given parameters and calls merge to merge the retrieved branch heads into the current branch. With `rebase`, it runs rebase instead of merge. 33 | 34 | Default values for `remote` and `branch` are read from the "remote" and "merge" configuration for the current branch. 35 | 36 | Assume the following history exists and the current branch is "master": 37 | 38 | ---- 39 | A---B---C master on origin 40 | / 41 | D---E---F---G master 42 | ^ 43 | origin/master in your repository 44 | ---- 45 | 46 | Then "git pull" will fetch and replay the changes from the remote master branch since it diverged from the local master (i.e., E) until its current commit `C` on top of master and record the result in a new commit along with the names of the two parent commits and a log message from the user describing the changes. 47 | 48 | ---- 49 | A---B---C origin/master 50 | / \ 51 | D---E---F---G---H master 52 | ---- 53 | 54 | == Options 55 | 56 | remote:: (`String`, default `null`) The "remote" repository that is source of a pull operation. This parameter can be either a URL or the name of a remote. 57 | branch:: (`String`, default `null`) The remote branch to pull. 58 | rebase:: (`boolean`, default `false`) When true, rebase the current branch on top of the upstream branch after fetching. If there is a remote-tracking branch corresponding to the upstream branch and the upstream branch was rebased since last fetched, the rebase uses that information to avoid rebasing non-local changes. 59 | 60 | == Examples 61 | 62 | == See Also 63 | 64 | - link:https://git-scm.com/docs/git-pull[git-pull] 65 | - xref:grgit-fetch.adoc[grgit-fetch] 66 | - xref:grgit-push.adoc[grgit-push] 67 | - xref:grgit-authentication.adoc[grgit-authentication] 68 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-reference.adoc: -------------------------------------------------------------------------------- 1 | = Grgit Reference 2 | 3 | include::partial$reference.adoc[] 4 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-remote.adoc: -------------------------------------------------------------------------------- 1 | = grgit-remote 2 | 3 | == Name 4 | 5 | grgit-remote - Manage set of tracked repositories 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.remote.list() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.remote.add(name: , url: , pushUrl: , 17 | fetchRefSpecs: [, ...], pushRefSpecs: [, ...], 18 | mirror: ) 19 | ---- 20 | 21 | [source, groovy] 22 | ---- 23 | grgit.remote.add { 24 | name = 25 | url = 26 | pushUrl = 27 | fetchRefSpecs = [, ...] 28 | pushRefSpecs = [, ...] 29 | mirror = 30 | } 31 | ---- 32 | 33 | == Description 34 | 35 | Manage the set of repositories ("remotes") whose branches you track. 36 | 37 | `list()` returns a `List` (link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Remote.groovy[Remote]) of all remotes configured for the repo. 38 | `add()` returns the newly configured link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Remote.groovy[Remote] 39 | 40 | == Options 41 | 42 | === add 43 | 44 | name:: (`String`, default `null`) Name of the new remote 45 | url:: (`String`, default `null`) URL to fetch the remote repository from. 46 | pushUrl:: (`String`, default `null`) URL to push to for this remote. If omitted, `url` is used for push. 47 | fetchRefSpecs:: (`List`, default `[+refs/heads/*:refs/remotes//*]`) default refspecs to use when fetching from this remote. 48 | pushRefSpecs:: (`List`, default `[]`) default refspecs to use when pushing to this remote. 49 | mirror:: (`boolean`, default `false`) If `true` makes xref:grgit-push.adoc[grgit-push] always behave as if `mirror` is specified. 50 | 51 | == Examples 52 | 53 | == See Also 54 | 55 | - link:https://git-scm.com/docs/git-remote[git-remote] 56 | - xref:grgit-push.adoc[grgit-push] 57 | - xref:grgit-pull.adoc[grgit-pull] 58 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-remove.adoc: -------------------------------------------------------------------------------- 1 | = grgit-remove 2 | 3 | == Name 4 | 5 | grgit-remove - Remove files from the working tree and from the index 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.remove(patterns: ['', ...], cached: ) 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.remove { 17 | patterns = ['', ...] 18 | cached = 19 | } 20 | ---- 21 | 22 | == Description 23 | 24 | Remove files from the index, or from the working tree and the index. `remove` will not remove a file from just your working directory. The files being removed have to be identical to the tip of the branch, and no updates to their contents can be staged in the index. When `cached` is given, the staged content has to match either the tip of the branch or the file on disk, allowing the file to be removed from just the index. 25 | 26 | == Options 27 | 28 | patterns:: (`Set`, default `[]`) Files to remove. A leading directory name (e.g. `dir` to remove `dir/file1` and `dir/file2`) can be given to remove all files in the directory, and recursively all sub-directories. 29 | cached:: (`boolean`, default `false`) Use this option to unstage and remove paths only from the index. Working tree files, whether modified or not, will be left alone. 30 | 31 | == Examples 32 | 33 | Remove specific file or directory from both the index and working tree. 34 | 35 | [source, groovy] 36 | ---- 37 | grgit.remove(patterns: ['1.txt', 'some/dir']) 38 | ---- 39 | 40 | Remove specific file or directory from the index, but leave the in the working tree. 41 | 42 | [source, groovy] 43 | ---- 44 | grgit.remove(patterns: ['1.txt', 'some/dir'], cached: true) 45 | ---- 46 | 47 | == See Also 48 | 49 | - link:https://git-scm.com/docs/git-rm[git-rm] 50 | - xref:grgit-add.adoc[grgit-add] 51 | - xref:grgit-commit.adoc[grgit-commit] 52 | - xref:grgit-status.adoc[grgit-status] 53 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-resolve.adoc: -------------------------------------------------------------------------------- 1 | = grgit-resolve 2 | 3 | == Name 4 | 5 | grgit-resolve - Resolves objects to various types 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.resolve.toObjectId() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.resolve.toCommit() 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.resolve.toBranch() 22 | ---- 23 | 24 | [source, groovy] 25 | ---- 26 | grgit.resolve.toBranchName() 27 | ---- 28 | 29 | [source, groovy] 30 | ---- 31 | grgit.resolve.toTag() 32 | ---- 33 | 34 | [source, groovy] 35 | ---- 36 | grgit.resolve.toTagName() 37 | ---- 38 | 39 | [source, groovy] 40 | ---- 41 | grgit.resolve.toRevisionString() 42 | ---- 43 | 44 | == Description 45 | 46 | Various methods to resolve objects to types needed by Grgit operations. These are used to normalize the input, allowing the caller more flexibility in providing the data they have rather than having to convert it ahead of time. 47 | 48 | == Options 49 | 50 | toObjectId:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy[Commit], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Branch.groovy[Branch], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Ref.groovy[Ref] 51 | 52 | toCommit:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy[Commit], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Branch.groovy[Branch], String, GString 53 | 54 | toBranch:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Branch.groovy[Branch], String, GString 55 | 56 | toBranchName:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Branch.groovy[Branch], String, GString 57 | 58 | toTag:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag], String, GString 59 | 60 | toTagName:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag], String, GString 61 | 62 | toRevisionString:: Accepts link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy[Commit], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag], link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Branch.groovy[Branch], String, GString 63 | 64 | == Examples 65 | 66 | == See Also 67 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-revert.adoc: -------------------------------------------------------------------------------- 1 | = grgit-revert 2 | 3 | == Name 4 | 5 | grgit-revert - Revert some existing commits 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.revert(commits: [, ...]) 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.revert { 17 | commits = ['', ...] 18 | } 19 | ---- 20 | 21 | == Description 22 | 23 | 24 | Given one or more existing commits, revert the changes that the related patches introduce, and record some new commits that record them. This requires your working tree to be clean (no modifications from the HEAD commit). 25 | 26 | Note: git revert is used to record some new commits to reverse the effect of some earlier commits (often only a faulty one). If you want to throw away all uncommitted changes in your working directory, you should see xref:grgit-reset.adoc[grgit-reset], particularly the `hard` option. Take care with these alternatives as they will discard uncommitted changes in your working directory. 27 | 28 | Returns a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy[Commit] representing the new `HEAD`. 29 | 30 | == Options 31 | 32 | commits:: (`List`, default: `[]]`) Commits to revert. For a more complete list of ways to spell commit names, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toCommit` method). 33 | 34 | == Examples 35 | 36 | [source, groovy] 37 | ---- 38 | grgit.revert(commits: ['1234567', '1234568']) 39 | ---- 40 | 41 | == See Also 42 | 43 | - link:https://git-scm.com/docs/git-revert[git-revert] 44 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-show.adoc: -------------------------------------------------------------------------------- 1 | = grgit-show 2 | 3 | == Name 4 | 5 | grgit-show - Show a commit 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.show() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.show(commit: ) 17 | ---- 18 | 19 | [source, groovy] 20 | ---- 21 | grgit.show { 22 | commit = 23 | } 24 | ---- 25 | 26 | == Description 27 | 28 | Shows a commit including it's message and diff. 29 | 30 | Returns a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/CommitDiff.groovy[CommitDiff] for the given commit. 31 | 32 | == Options 33 | 34 | commit:: (`Object`, default: `HEAD`) A revstring-ish object naming the commit to be shown. Commit-ish object names to include the history of in the output. For a more complete list of ways to specify a revstring, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toRevisionString` method). 35 | 36 | == Examples 37 | 38 | == See Also 39 | 40 | - link:https://git-scm.com/docs/git-show[git-show] 41 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-status.adoc: -------------------------------------------------------------------------------- 1 | = grgit-status 2 | 3 | == Name 4 | 5 | grgit-status - Show the working tree status 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.status() 12 | ---- 13 | 14 | == Description 15 | 16 | Displays paths that have differences between the index file and the current `HEAD` commit, paths that have differences between the working tree and the index file, and paths in the working tree that are not tracked by Git (and are not ignored by gitignore). The first are what you would commit by running `commit`; the second and third are what you could commit by running `add` before running `commit`. 17 | 18 | Returns a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Status.groovy[Status] instance detailing the paths that differ. 19 | 20 | == Options 21 | 22 | _None_ 23 | 24 | == Examples 25 | 26 | == See Also 27 | 28 | - link:https://git-scm.com/docs/git-status[git-status] 29 | - xref:grgit-add.adoc[grgit-add] 30 | - xref:grgit-remove.adoc[grgit-remove] 31 | - xref:grgit-commit.adoc[grgit-commit] 32 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/grgit-tag.adoc: -------------------------------------------------------------------------------- 1 | = grgit-tag 2 | 3 | == Name 4 | 5 | grgit-tag - Create, list, or delete tag object 6 | 7 | == Synopsis 8 | 9 | [source, groovy] 10 | ---- 11 | grgit.tag.list() 12 | ---- 13 | 14 | [source, groovy] 15 | ---- 16 | grgit.tag.add(name: , pointsTo: , force: , 17 | annotate: , message: , tagger: ) 18 | ---- 19 | 20 | [source, groovy] 21 | ---- 22 | grgit.tag.remove(names: [, ...]) 23 | ---- 24 | 25 | == Description 26 | 27 | 28 | `grgit.tag.list()`:: Returns a list of tags (link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag]). 29 | `grgit.tag.add(name: , pointsTo: , force: , annotate: , message: , tagger: )`:: Creates a new tag named `` pointing at ``. Returns the created link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy[Tag]. 30 | `grgit.tag.remove(names: [, ...])`:: Removes one or more tages. Returns a `List` of tag names removed. 31 | 32 | == Options 33 | 34 | === add 35 | 36 | name:: (`String`, default `null`) Name of the tag 37 | message:: (`String`, default `null`) Use the given as the commit message. 38 | tagger:: (`Person`, default `null`) Override the tagger recorded in the tag. This must be a link:https://github.com/ajoberstar/grgit/blob/{page-component-version}/grgit-core/src/main/groovy/org/ajoberstar/grgit/Person.groovy[Person]. 39 | annotate:: (`boolean`, default `true`) Make an unsigned, annotated tag object 40 | force:: (`boolean`, default `false`) Replace an existing tag with the given name (instead of failing) 41 | pointsTo:: (`Object`, default `null`) Point new tag at this commit. For a more complete list of acceptable inputs, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toRevisionString` method). 42 | 43 | === remove 44 | 45 | names:: (`List`, default `[]`) Names of the tags. For a more complete list of acceptable inputs, see xref:grgit-resolve.adoc[grgit-resolve] (specifically the `toTagName` method). 46 | 47 | == Examples 48 | 49 | To list all tags. 50 | 51 | [source, groovy] 52 | ---- 53 | def tags = grgit.tag.list() 54 | ---- 55 | 56 | Add an annotated tag. 57 | 58 | [source, groovy] 59 | ---- 60 | grgit.tag.add(name: 'new-tag') 61 | grgit.tag.add(name: 'new-tag', message: 'Some message') 62 | grgit.tag.add(name: 'new-tag', annotate: true) 63 | ---- 64 | 65 | Add an unannotated tag. 66 | 67 | [source, groovy] 68 | ---- 69 | grgit.tag.add(name: 'new-tag', annotate: false) 70 | ---- 71 | 72 | Add a tag starting at a specific commit. 73 | 74 | [source, groovy] 75 | ---- 76 | grgit.tag.add(name: 'new-tag', pointsTo: 'other-branch') 77 | ---- 78 | 79 | Overwrite an existing tag. 80 | 81 | [source, groovy] 82 | ---- 83 | grgit.tag.add(name: 'existing-tag', force: true) 84 | ---- 85 | 86 | Remove tags. 87 | 88 | [source, groovy] 89 | ---- 90 | def removedTags = grgit.tag.remove(names: ['the-tag']) 91 | ---- 92 | 93 | == See Also 94 | 95 | - link:https://git-scm.com/docs/git-tag[git-tag] 96 | -------------------------------------------------------------------------------- /docs/modules/ROOT/partials/reference.adoc: -------------------------------------------------------------------------------- 1 | * Setup and Config 2 | ** xref:grgit-authentication.adoc[] 3 | ** xref:grgit-gradle.adoc[] 4 | * Getting and Creating Projects 5 | ** xref:grgit-init.adoc[] 6 | ** xref:grgit-clone.adoc[] 7 | ** xref:grgit-open.adoc[] 8 | * Basic Snapshotting 9 | ** xref:grgit-add.adoc[] 10 | ** xref:grgit-status.adoc[] 11 | ** xref:grgit-commit.adoc[] 12 | ** xref:grgit-reset.adoc[] 13 | ** xref:grgit-remove.adoc[] 14 | * Branching and Merging 15 | ** xref:grgit-branch.adoc[] 16 | ** xref:grgit-checkout.adoc[] 17 | ** xref:grgit-merge.adoc[] 18 | ** xref:grgit-tag.adoc[] 19 | * Sharing and Updating Projects 20 | ** xref:grgit-fetch.adoc[] 21 | ** xref:grgit-pull.adoc[] 22 | ** xref:grgit-push.adoc[] 23 | ** xref:grgit-remote.adoc[] 24 | * Inspection and Comparison 25 | ** xref:grgit-head.adoc[] 26 | ** xref:grgit-show.adoc[] 27 | ** xref:grgit-log.adoc[] 28 | ** xref:grgit-describe.adoc[] 29 | ** xref:grgit-resolve.adoc[] 30 | ** xref:grgit-isAncestorOf.adoc[] 31 | * Patching 32 | ** xref:grgit-apply.adoc[] 33 | ** xref:grgit-revert.adoc[] 34 | * Administration 35 | ** xref:grgit-clean.adoc[] 36 | * Plumbing 37 | ** xref:grgit-lsremote.adoc[] 38 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajoberstar/grgit/311e7b00529fd3c1bab4b60266e4a2a1c15f1075/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /grgit-core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.ajoberstar.defaults.java-library") 3 | id("groovy") 4 | } 5 | 6 | group = "org.ajoberstar.grgit" 7 | description = "The Groovy way to use Git" 8 | 9 | mavenCentral { 10 | developerName.set("Andrew Oberstar") 11 | developerEmail.set("andrew@ajoberstar.org") 12 | githubOwner.set("ajoberstar") 13 | githubRepository.set("grgit") 14 | } 15 | 16 | java { 17 | toolchain { 18 | languageVersion.set(JavaLanguageVersion.of(11)) 19 | } 20 | } 21 | 22 | val transform1 by sourceSets.creating 23 | val transform2 by sourceSets.creating 24 | 25 | dependencies { 26 | "transform1Implementation"("org.codehaus.groovy:groovy:[3.0.9, 4.0)") 27 | 28 | "transform2Implementation"("org.codehaus.groovy:groovy:[3.0.9, 4.0)") 29 | "transform2Implementation"(transform1.output) 30 | 31 | api("org.codehaus.groovy:groovy:[3.0.9, 4.0)") 32 | api("org.eclipse.jgit:org.eclipse.jgit:[6.0, 7.0)") 33 | api(transform2.output) 34 | } 35 | 36 | testing { 37 | suites { 38 | val test by getting(JvmTestSuite::class) { 39 | useSpock("2.3-groovy-3.0") 40 | 41 | dependencies { 42 | implementation("org.codehaus.groovy:groovy:[3.0.9, 4.0)") 43 | implementation("org.junit.jupiter:junit-jupiter-api:latest.release") 44 | 45 | // logging 46 | implementation("org.slf4j:slf4j-api:latest.release") 47 | runtimeOnly("org.slf4j:slf4j-simple:latest.release") 48 | } 49 | } 50 | } 51 | } 52 | 53 | tasks.named("jar") { 54 | manifest { 55 | attributes.put("Automatic-Module-Name", "org.ajoberstar.grgit") 56 | } 57 | from(transform1.output) 58 | from(transform2.output) 59 | } 60 | -------------------------------------------------------------------------------- /grgit-core/gradle.lockfile: -------------------------------------------------------------------------------- 1 | # This is a Gradle generated file for dependency locking. 2 | # Manual edits can break the build and are not advised. 3 | # This file is expected to be part of source control. 4 | com.googlecode.javaewah:JavaEWAH:1.2.3=compileClasspath,default,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 5 | commons-codec:commons-codec:1.16.0=default 6 | commons-codec:commons-codec:1.17.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 7 | org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath 8 | org.codehaus.groovy:groovy:3.0.12=testCompileClasspath,testRuntimeClasspath 9 | org.codehaus.groovy:groovy:3.0.19=default 10 | org.codehaus.groovy:groovy:3.0.20=transformCompileClasspath,transformRuntimeClasspath 11 | org.codehaus.groovy:groovy:3.0.22=compileClasspath,runtimeClasspath,transform1CompileClasspath,transform1RuntimeClasspath,transform2CompileClasspath,transform2RuntimeClasspath 12 | org.eclipse.jgit:org.eclipse.jgit:6.10.0.202406032230-r=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 13 | org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r=default 14 | org.hamcrest:hamcrest:2.2=testCompileClasspath,testRuntimeClasspath 15 | org.junit.jupiter:junit-jupiter-api:5.11.2=testCompileClasspath,testRuntimeClasspath 16 | org.junit.platform:junit-platform-commons:1.11.2=testCompileClasspath,testRuntimeClasspath 17 | org.junit.platform:junit-platform-engine:1.11.2=testCompileClasspath,testRuntimeClasspath 18 | org.junit.platform:junit-platform-launcher:1.11.2=testRuntimeClasspath 19 | org.junit:junit-bom:5.11.2=testCompileClasspath,testRuntimeClasspath 20 | org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath 21 | org.slf4j:slf4j-api:1.7.36=compileClasspath,default,runtimeClasspath 22 | org.slf4j:slf4j-api:2.1.0-alpha1=testCompileClasspath,testRuntimeClasspath 23 | org.slf4j:slf4j-simple:2.1.0-alpha1=testRuntimeClasspath 24 | org.spockframework:spock-core:2.3-groovy-3.0=testCompileClasspath,testRuntimeClasspath 25 | empty=annotationProcessor,archives,signatures,testAnnotationProcessor,transform1AnnotationProcessor,transform2AnnotationProcessor,transformAnnotationProcessor 26 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Branch.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | import org.eclipse.jgit.lib.Repository 6 | 7 | /** 8 | * A branch. 9 | * @since 0.2.0 10 | */ 11 | @Immutable 12 | class Branch { 13 | /** 14 | * The fully qualified name of this branch. 15 | */ 16 | String fullName 17 | 18 | /** 19 | * This branch's upstream branch. {@code null} if this branch isn't 20 | * tracking an upstream. 21 | */ 22 | Branch trackingBranch 23 | 24 | /** 25 | * The simple name of the branch. 26 | * @return the simple name 27 | */ 28 | String getName() { 29 | return Repository.shortenRefName(fullName) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/BranchStatus.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | /** 6 | * The tracking status of a branch. 7 | * @since 0.2.0 8 | */ 9 | @Immutable 10 | class BranchStatus { 11 | /** 12 | * The branch this object is for. 13 | */ 14 | Branch branch 15 | 16 | /** 17 | * The number of commits this branch is ahead of its upstream. 18 | */ 19 | int aheadCount 20 | 21 | /** 22 | * The number of commits this branch is behind its upstream. 23 | */ 24 | int behindCount 25 | } 26 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Commit.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | import java.time.ZonedDateTime 5 | 6 | /** 7 | * A commit. 8 | * @since 0.1.0 9 | */ 10 | @Immutable(knownImmutableClasses=[ZonedDateTime]) 11 | class Commit { 12 | /** 13 | * The full hash of the commit. 14 | */ 15 | String id 16 | 17 | /** 18 | * The abbreviated hash of the commit. 19 | */ 20 | String abbreviatedId 21 | 22 | /** 23 | * Hashes of any parent commits. 24 | */ 25 | List parentIds 26 | 27 | /** 28 | * The author of the changes in the commit. 29 | */ 30 | Person author 31 | 32 | /** 33 | * The committer of the changes in the commit. 34 | */ 35 | Person committer 36 | 37 | /** 38 | * The time the commit was created with the time zone of the committer, if available. 39 | */ 40 | ZonedDateTime dateTime 41 | 42 | /** 43 | * The full commit message. 44 | */ 45 | String fullMessage 46 | 47 | /** 48 | * The shortened commit message. 49 | */ 50 | String shortMessage 51 | 52 | /** 53 | * The time the commit was created in seconds since "the epoch". 54 | * @return the time 55 | * @deprecated use Commit#dateTime 56 | */ 57 | @Deprecated 58 | long getTime() { 59 | return dateTime.toEpochSecond() 60 | } 61 | 62 | /** 63 | * The time the commit was created. 64 | * @return the date 65 | * @deprecated use Commit#dateTime 66 | */ 67 | @Deprecated 68 | Date getDate() { 69 | return Date.from(dateTime.toInstant()) 70 | } 71 | 72 | /** 73 | * The first {@code length} characters of the commit hash. 74 | * @param length the number of characters to abbreviate the 75 | * hash. 76 | */ 77 | @Deprecated 78 | String getAbbreviatedId(int length) { 79 | return id[0..(length - 1)] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/CommitDiff.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | import groovy.transform.ToString 5 | 6 | @Immutable 7 | @ToString(includeNames=true) 8 | class CommitDiff { 9 | Commit commit 10 | 11 | Set added = [] 12 | 13 | Set copied = [] 14 | 15 | Set modified = [] 16 | 17 | Set removed = [] 18 | 19 | Set renamed = [] 20 | 21 | Map renamings = [:] 22 | 23 | /** 24 | * Gets all changed files. 25 | * @return all changed files 26 | */ 27 | Set getAllChanges() { 28 | return added + copied + modified + removed + renamed 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Credentials.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Canonical 4 | 5 | /** 6 | * Credentials to use for remote operations. 7 | * @since 0.2.0 8 | */ 9 | @Canonical 10 | class Credentials { 11 | final String username 12 | final String password 13 | 14 | String getUsername() { 15 | return username ?: '' 16 | } 17 | 18 | String getPassword() { 19 | return password ?: '' 20 | } 21 | 22 | boolean isPopulated() { 23 | return username != null 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/DiffEntry.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | import groovy.transform.ToString 5 | 6 | @Immutable 7 | @ToString(includeNames=true) 8 | class DiffEntry { 9 | /** General type of change a single file-level patch describes. */ 10 | enum ChangeType { 11 | ADD, 12 | MODIFY, 13 | DELETE, 14 | RENAME, 15 | COPY; 16 | } 17 | 18 | /** General type of change indicated by the patch. */ 19 | ChangeType changeType; 20 | 21 | /** 22 | * Get the old name associated with this file. 23 | *

24 | * The meaning of the old name can differ depending on the semantic meaning 25 | * of this patch: 26 | *

    27 | *
  • file add: always /dev/null
  • 28 | *
  • file modify: always {@link #newPath}
  • 29 | *
  • file delete: always the file being deleted
  • 30 | *
  • file copy: source file the copy originates from
  • 31 | *
  • file rename: source file the rename originates from
  • 32 | *
33 | * 34 | */ 35 | String oldPath; 36 | 37 | /** 38 | * Get the new name associated with this file. 39 | *

40 | * The meaning of the new name can differ depending on the semantic meaning 41 | * of this patch: 42 | *

    43 | *
  • file add: always the file being created
  • 44 | *
  • file modify: always {@link #oldPath}
  • 45 | *
  • file delete: always /dev/null
  • 46 | *
  • file copy: destination file the copy ends up at
  • 47 | *
  • file rename: destination file the rename ends up at
  • 48 | *
49 | * 50 | */ 51 | String newPath; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Person.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | /** 6 | * A person. 7 | * @since 0.1.0 8 | */ 9 | @Immutable 10 | class Person { 11 | /** 12 | * Name of person. 13 | */ 14 | String name 15 | 16 | /** 17 | * Email address of person. 18 | */ 19 | String email 20 | } 21 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/PushException.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit; 2 | 3 | import org.eclipse.jgit.api.errors.TransportException; 4 | 5 | public class PushException extends TransportException { 6 | public PushException(String message) { 7 | super(message); 8 | } 9 | 10 | public PushException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Ref.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | import org.eclipse.jgit.lib.Repository 6 | 7 | /** 8 | * A ref. 9 | * @since 2.0.0 10 | */ 11 | @Immutable 12 | class Ref { 13 | /** 14 | * The fully qualified name of this ref. 15 | */ 16 | String fullName 17 | 18 | /** 19 | * The simple name of the ref. 20 | * @return the simple name 21 | */ 22 | String getName() { 23 | return Repository.shortenRefName(fullName) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Remote.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | /** 6 | * Remote repository. 7 | * @since 0.4.0 8 | */ 9 | @Immutable 10 | class Remote { 11 | /** 12 | * Name of the remote. 13 | */ 14 | String name 15 | 16 | /** 17 | * URL to fetch from. 18 | */ 19 | String url 20 | 21 | /** 22 | * URL to push to. 23 | */ 24 | String pushUrl 25 | 26 | /** 27 | * Specs to fetch from the remote. 28 | */ 29 | List fetchRefSpecs = [] 30 | 31 | /** 32 | * Specs to push to the remote. 33 | */ 34 | List pushRefSpecs = [] 35 | 36 | /** 37 | * Whether or not pushes will mirror the repository. 38 | */ 39 | boolean mirror 40 | } 41 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Repository.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | import org.eclipse.jgit.api.Git 6 | 7 | /** 8 | * A repository. 9 | * @since 0.1.0 10 | */ 11 | @Immutable(knownImmutableClasses=[Git, File, Credentials]) 12 | class Repository { 13 | /** 14 | * The directory the repository is contained in. 15 | */ 16 | File rootDir 17 | 18 | /** 19 | * The JGit instance opened for this repository. 20 | */ 21 | Git jgit 22 | 23 | /** 24 | * The credentials used when talking to remote repositories. 25 | */ 26 | Credentials credentials 27 | 28 | @Override 29 | String toString() { 30 | return "Repository(${rootDir.canonicalPath})" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Status.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.EqualsAndHashCode 4 | import groovy.transform.ToString 5 | 6 | /** 7 | * Status of the current working tree and index. 8 | */ 9 | @EqualsAndHashCode 10 | @ToString(includeNames=true) 11 | class Status { 12 | final Changes staged 13 | final Changes unstaged 14 | final Set conflicts 15 | 16 | Status(Map args = [:]) { 17 | def invalidArgs = args.keySet() - ['staged', 'unstaged', 'conflicts'] 18 | if (invalidArgs) { 19 | throw new IllegalArgumentException("Following keys are not supported: ${invalidArgs}") 20 | } 21 | this.staged = 'staged' in args ? new Changes(args.staged) : new Changes() 22 | this.unstaged = 'unstaged' in args ? new Changes(args.unstaged) : new Changes() 23 | this.conflicts = 'conflicts' in args ? args.conflicts : [] 24 | } 25 | 26 | @EqualsAndHashCode 27 | @ToString(includeNames=true) 28 | class Changes { 29 | final Set added 30 | final Set modified 31 | final Set removed 32 | 33 | Changes(Map args = [:]) { 34 | def invalidArgs = args.keySet() - ['added', 'modified', 'removed'] 35 | if (invalidArgs) { 36 | throw new IllegalArgumentException("Following keys are not supported: ${invalidArgs}") 37 | } 38 | this.added = 'added' in args ? args.added : [] 39 | this.modified = 'modified' in args ? args.modified : [] 40 | this.removed = 'removed' in args ? args.removed : [] 41 | } 42 | 43 | /** 44 | * Gets all changed files. 45 | * @return all changed files 46 | */ 47 | Set getAllChanges() { 48 | return added + modified + removed 49 | } 50 | } 51 | 52 | /** 53 | * Whether the repository has any changes or conflicts. 54 | * @return {@code true} if there are no changes either staged or unstaged or 55 | * any conflicts, {@code false} otherwise 56 | */ 57 | boolean isClean() { 58 | return (staged.allChanges + unstaged.allChanges + conflicts).empty 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/Tag.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import groovy.transform.Immutable 4 | 5 | import java.time.ZonedDateTime 6 | 7 | import org.eclipse.jgit.lib.Repository 8 | 9 | /** 10 | * A tag. 11 | * @since 0.2.0 12 | */ 13 | @Immutable(knownImmutableClasses=[ZonedDateTime]) 14 | class Tag { 15 | /** 16 | * The commit this tag points to. 17 | */ 18 | Commit commit 19 | 20 | /** 21 | * The person who created the tag. 22 | */ 23 | Person tagger 24 | 25 | /** 26 | * The full name of this tag. 27 | */ 28 | String fullName 29 | 30 | /** 31 | * The full tag message. 32 | */ 33 | String fullMessage 34 | 35 | /** 36 | * The shortened tag message. 37 | */ 38 | String shortMessage 39 | 40 | /** 41 | * The time the commit was created with the time zone of the committer, if available. 42 | */ 43 | ZonedDateTime dateTime 44 | 45 | /** 46 | * The simple name of this tag. 47 | * @return the simple name 48 | */ 49 | String getName() { 50 | return Repository.shortenRefName(fullName) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/auth/AuthConfig.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.auth 2 | 3 | import org.ajoberstar.grgit.Credentials 4 | import org.eclipse.jgit.util.SystemReader 5 | import org.slf4j.Logger 6 | import org.slf4j.LoggerFactory 7 | 8 | /** 9 | * Stores configuration options for how to authenticate with remote 10 | * repositories. 11 | * @since 0.2.0 12 | * @see grgit-authentication 13 | */ 14 | class AuthConfig { 15 | private static final Logger logger = LoggerFactory.getLogger(AuthConfig) 16 | 17 | static final String USERNAME_OPTION = 'org.ajoberstar.grgit.auth.username' 18 | static final String PASSWORD_OPTION = 'org.ajoberstar.grgit.auth.password' 19 | 20 | static final String USERNAME_ENV_VAR = 'GRGIT_USER' 21 | static final String PASSWORD_ENV_VAR = 'GRGIT_PASS' 22 | 23 | private final Map props 24 | private final Map env 25 | 26 | private AuthConfig(Map props, Map env) { 27 | this.props = props 28 | this.env = env 29 | 30 | GrgitSystemReader.install() 31 | logger.debug('If SSH is used, the following external command (if non-null) will be used instead of JSch: {}', SystemReader.instance.getenv('GIT_SSH')) 32 | } 33 | 34 | /** 35 | * Constructs and returns a {@link Credentials} instance reflecting the 36 | * settings in the system properties. 37 | * @return a credentials instance reflecting the settings in the system 38 | * properties, or, if the username isn't set, {@code null} 39 | */ 40 | Credentials getHardcodedCreds() { 41 | String username = props[USERNAME_OPTION] ?: env[USERNAME_ENV_VAR] 42 | String password = props[PASSWORD_OPTION] ?: env[PASSWORD_ENV_VAR] 43 | return new Credentials(username, password) 44 | } 45 | 46 | /** 47 | * Factory method to construct an authentication configuration from the 48 | * given properties and environment. 49 | * @param properties the properties to use in this configuration 50 | * @param env the environment vars to use in this configuration 51 | * @return the constructed configuration 52 | * @throws IllegalArgumentException if force is set to an invalid option 53 | */ 54 | static AuthConfig fromMap(Map props, Map env = [:]) { 55 | return new AuthConfig(props, env) 56 | } 57 | 58 | /** 59 | * Factory method to construct an authentication configuration from the 60 | * current system properties and environment variables. 61 | * @return the constructed configuration 62 | * @throws IllegalArgumentException if force is set to an invalid option 63 | */ 64 | static AuthConfig fromSystem() { 65 | return fromMap(System.properties, System.env) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/auth/GrgitSystemReader.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.auth; 2 | 3 | import java.io.File; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Optional; 10 | import java.util.function.Function; 11 | import java.util.regex.Pattern; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.Stream; 14 | 15 | import org.eclipse.jgit.util.SystemReader; 16 | 17 | public class GrgitSystemReader extends SystemReader.Delegate { 18 | private static final Pattern PATH_SPLITTER = Pattern.compile(Pattern.quote(File.pathSeparator)); 19 | private final String gitSsh; 20 | 21 | public GrgitSystemReader(SystemReader delegate, String gitSsh) { 22 | super(delegate); 23 | this.gitSsh = gitSsh; 24 | } 25 | 26 | @Override 27 | public String getenv(String variable) { 28 | String value = super.getenv(variable); 29 | if ("GIT_SSH".equals(variable) && value == null) { 30 | return gitSsh; 31 | } else { 32 | return value; 33 | } 34 | } 35 | 36 | public static void install() { 37 | SystemReader current = SystemReader.getInstance(); 38 | 39 | String gitSsh = Stream.of("ssh", "plink") 40 | .map(GrgitSystemReader::findExecutable) 41 | .filter(Optional::isPresent) 42 | .map(Optional::get) 43 | .findFirst() 44 | .orElse(null); 45 | 46 | SystemReader grgit = new GrgitSystemReader(current, gitSsh); 47 | SystemReader.setInstance(grgit); 48 | } 49 | 50 | private static Optional findExecutable(String exe) { 51 | List extensions = Optional.ofNullable(System.getenv("PATHEXT")) 52 | .map(PATH_SPLITTER::splitAsStream) 53 | .map(stream -> stream.collect(Collectors.toList())) 54 | .orElse(Collections.emptyList()); 55 | 56 | Function> getCandidatePaths = dir -> { 57 | // assume PATHEXT is only set on Windows 58 | if (extensions.isEmpty()) { 59 | return Stream.of(dir.resolve(exe)); 60 | } else { 61 | return extensions.stream() 62 | .map(ext -> dir.resolve(exe + ext)); 63 | } 64 | }; 65 | 66 | return PATH_SPLITTER.splitAsStream(System.getenv("PATH")) 67 | .map(Paths::get) 68 | .flatMap(getCandidatePaths) 69 | .filter(Files::isExecutable) 70 | .map(Path::toAbsolutePath) 71 | .map(Path::toString) 72 | .findFirst(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/auth/TransportOpUtil.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.auth 2 | 3 | import org.ajoberstar.grgit.Credentials 4 | 5 | import org.eclipse.jgit.api.TransportCommand 6 | import org.eclipse.jgit.errors.UnsupportedCredentialItem 7 | import org.eclipse.jgit.transport.CredentialItem 8 | import org.eclipse.jgit.transport.CredentialsProvider 9 | import org.eclipse.jgit.transport.URIish 10 | import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider 11 | 12 | import org.slf4j.Logger 13 | import org.slf4j.LoggerFactory 14 | 15 | /** 16 | * Utility class that allows a JGit {@code TransportCommand} to be configured 17 | * to use additional authentication options. 18 | */ 19 | final class TransportOpUtil { 20 | private static final Logger logger = LoggerFactory.getLogger(TransportOpUtil) 21 | 22 | private TransportOpUtil() { 23 | throw new AssertionError('This class cannot be instantiated.') 24 | } 25 | 26 | /** 27 | * Configures the given transport command with the given credentials. 28 | * @param cmd the command to configure 29 | * @param credentials the hardcoded credentials to use, if not {@code null} 30 | */ 31 | static void configure(TransportCommand cmd, Credentials credentials) { 32 | AuthConfig config = AuthConfig.fromSystem() 33 | cmd.credentialsProvider = determineCredentialsProvider(config, credentials) 34 | } 35 | 36 | private static CredentialsProvider determineCredentialsProvider(AuthConfig config, Credentials credentials) { 37 | Credentials systemCreds = config.hardcodedCreds 38 | if (credentials?.populated) { 39 | logger.info('using hardcoded credentials provided programmatically') 40 | return new UsernamePasswordCredentialsProvider(credentials.username, credentials.password) 41 | } else if (systemCreds?.populated) { 42 | logger.info('using hardcoded credentials from system properties') 43 | return new UsernamePasswordCredentialsProvider(systemCreds.username, systemCreds.password) 44 | } else { 45 | return null 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/auth/package-info.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.auth 2 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/AddOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.eclipse.jgit.api.AddCommand 8 | 9 | /** 10 | * Adds files to the index. 11 | * @since 0.1.0 12 | * @see grgit-add 13 | * @see git-add Manual Page 14 | */ 15 | @Operation('add') 16 | class AddOp implements Callable { 17 | private final Repository repo 18 | 19 | /** 20 | * Patterns of files to add to the index. 21 | */ 22 | Set patterns = [] 23 | 24 | /** 25 | * {@code true} if changes to all currently tracked files should be added 26 | * to the index, {@code false} otherwise. 27 | */ 28 | boolean update = false 29 | 30 | AddOp(Repository repo) { 31 | this.repo = repo 32 | } 33 | 34 | Void call() { 35 | AddCommand cmd = repo.jgit.add() 36 | patterns.each { cmd.addFilepattern(it) } 37 | cmd.update = update 38 | cmd.call() 39 | return null 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/ApplyOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.ajoberstar.grgit.util.CoercionUtil 8 | import org.eclipse.jgit.api.ApplyCommand 9 | 10 | /** 11 | * Apply a patch to the index. 12 | * @since 0.1.0 13 | * @see grgit-apply 14 | * @see git-apply Manual Page 15 | */ 16 | @Operation('apply') 17 | class ApplyOp implements Callable { 18 | private final Repository repo 19 | 20 | /** 21 | * The patch file to apply to the index. 22 | * @see {@link CoercionUtil#toFile(Object)} 23 | */ 24 | Object patch 25 | 26 | ApplyOp(Repository repo) { 27 | this.repo = repo 28 | } 29 | 30 | Void call() { 31 | ApplyCommand cmd = repo.jgit.apply() 32 | if (!patch) { 33 | throw new IllegalStateException('Must set a patch file.') 34 | } 35 | CoercionUtil.toFile(patch).withInputStream { stream -> 36 | cmd.patch = stream 37 | cmd.call() 38 | return null 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/BranchAddOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Branch 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.service.ResolveService 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.api.CreateBranchCommand 11 | import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode 12 | import org.eclipse.jgit.lib.Ref 13 | 14 | /** 15 | * Adds a branch to the repository. Returns the newly created {@link Branch}. 16 | * @since 0.2.0 17 | * @see grgit-branch 18 | * @see git-branch Manual Page 19 | */ 20 | @Operation('add') 21 | class BranchAddOp implements Callable { 22 | private final Repository repo 23 | 24 | /** 25 | * The name of the branch to add. 26 | */ 27 | String name 28 | 29 | /** 30 | * The commit the branch should start at. If this is a remote branch 31 | * it will be automatically tracked. 32 | * @see {@link ResolveService#toRevisionString(Object)} 33 | */ 34 | Object startPoint 35 | 36 | /** 37 | * The tracking mode to use. If {@code null}, will use the default 38 | * behavior. 39 | */ 40 | Mode mode 41 | 42 | BranchAddOp(Repository repo) { 43 | this.repo = repo 44 | } 45 | 46 | Branch call() { 47 | if (mode && !startPoint) { 48 | throw new IllegalStateException('Cannot set mode if no start point.') 49 | } 50 | CreateBranchCommand cmd = repo.jgit.branchCreate() 51 | cmd.name = name 52 | cmd.force = false 53 | if (startPoint) { 54 | String rev = new ResolveService(repo).toRevisionString(startPoint) 55 | cmd.startPoint = rev 56 | } 57 | if (mode) { cmd.upstreamMode = mode.jgit } 58 | 59 | Ref ref = cmd.call() 60 | return JGitUtil.resolveBranch(repo, ref) 61 | } 62 | 63 | static enum Mode { 64 | TRACK(SetupUpstreamMode.TRACK), 65 | NO_TRACK(SetupUpstreamMode.NOTRACK) 66 | 67 | private final SetupUpstreamMode jgit 68 | 69 | Mode(SetupUpstreamMode jgit) { 70 | this.jgit = jgit 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/BranchChangeOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Branch 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.service.ResolveService 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.api.CreateBranchCommand 11 | import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode 12 | import org.eclipse.jgit.lib.Ref 13 | 14 | /** 15 | * Changes a branch's start point and/or upstream branch. Returns the changed {@link Branch}. 16 | * @since 0.2.0 17 | * @see grgit-branch 18 | * @see git-branch Manual Page 19 | */ 20 | @Operation('change') 21 | class BranchChangeOp implements Callable { 22 | private final Repository repo 23 | 24 | /** 25 | * The name of the branch to change. 26 | */ 27 | String name 28 | 29 | /** 30 | * The commit the branch should now start at. 31 | * @see {@link ResolveService#toRevisionString(Object)} 32 | */ 33 | Object startPoint 34 | 35 | /** 36 | * The tracking mode to use. 37 | */ 38 | Mode mode 39 | 40 | BranchChangeOp(Repository repo) { 41 | this.repo = repo 42 | } 43 | 44 | Branch call() { 45 | if (!JGitUtil.resolveBranch(repo, name)) { 46 | throw new IllegalStateException("Branch does not exist: ${name}") 47 | } 48 | if (!startPoint) { 49 | throw new IllegalArgumentException('Must set new startPoint.') 50 | } 51 | CreateBranchCommand cmd = repo.jgit.branchCreate() 52 | cmd.name = name 53 | cmd.force = true 54 | if (startPoint) { 55 | String rev = new ResolveService(repo).toRevisionString(startPoint) 56 | cmd.startPoint = rev 57 | } 58 | if (mode) { cmd.upstreamMode = mode.jgit } 59 | 60 | Ref ref = cmd.call() 61 | return JGitUtil.resolveBranch(repo, ref) 62 | } 63 | 64 | static enum Mode { 65 | TRACK(SetupUpstreamMode.TRACK), 66 | NO_TRACK(SetupUpstreamMode.NOTRACK) 67 | 68 | private final SetupUpstreamMode jgit 69 | 70 | Mode(SetupUpstreamMode jgit) { 71 | this.jgit = jgit 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/BranchListOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Branch 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.service.ResolveService 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.api.ListBranchCommand 11 | 12 | /** 13 | * Lists branches in the repository. Returns a list of {@link Branch}. 14 | * @since 0.2.0 15 | * @see grgit-branch 16 | * @see git-branch Manual Page 17 | */ 18 | @Operation('list') 19 | class BranchListOp implements Callable> { 20 | private final Repository repo 21 | 22 | /** 23 | * Which branches to return. 24 | */ 25 | Mode mode = Mode.LOCAL 26 | 27 | /** 28 | * Commit ref branches must contains 29 | */ 30 | Object contains = null 31 | 32 | BranchListOp(Repository repo) { 33 | this.repo = repo 34 | } 35 | 36 | List call() { 37 | ListBranchCommand cmd = repo.jgit.branchList() 38 | cmd.listMode = mode.jgit 39 | if (contains) { 40 | cmd.contains = new ResolveService(repo).toRevisionString(contains) 41 | } 42 | return cmd.call().collect { 43 | JGitUtil.resolveBranch(repo, it.name) 44 | } 45 | } 46 | 47 | static enum Mode { 48 | ALL(ListBranchCommand.ListMode.ALL), 49 | REMOTE(ListBranchCommand.ListMode.REMOTE), 50 | LOCAL(null) 51 | 52 | private final ListBranchCommand.ListMode jgit 53 | 54 | private Mode(ListBranchCommand.ListMode jgit) { 55 | this.jgit = jgit 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/BranchRemoveOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.ajoberstar.grgit.service.ResolveService 8 | import org.eclipse.jgit.api.DeleteBranchCommand 9 | 10 | /** 11 | * Removes one or more branches from the repository. Returns a list of 12 | * the fully qualified branch names that were removed. 13 | * @since 0.2.0 14 | * @see grgit-branch 15 | * @see git-branch Manual Page 16 | */ 17 | @Operation('remove') 18 | class BranchRemoveOp implements Callable> { 19 | private final Repository repo 20 | 21 | /** 22 | * List of all branche names to remove. 23 | * @see {@link ResolveService#toBranchName(Object)} 24 | */ 25 | List names = [] 26 | 27 | /** 28 | * If {@code false} (the default), only remove branches that 29 | * are merged into another branch. If {@code true} will delete 30 | * regardless. 31 | */ 32 | boolean force = false 33 | 34 | BranchRemoveOp(Repository repo) { 35 | this.repo = repo 36 | } 37 | 38 | List call() { 39 | DeleteBranchCommand cmd = repo.jgit.branchDelete() 40 | cmd.branchNames = names.collect { new ResolveService(repo).toBranchName(it) } 41 | cmd.force = force 42 | 43 | return cmd.call() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/BranchStatusOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Branch 6 | import org.ajoberstar.grgit.BranchStatus 7 | import org.ajoberstar.grgit.Repository 8 | import org.ajoberstar.grgit.internal.Operation 9 | import org.ajoberstar.grgit.service.ResolveService 10 | import org.eclipse.jgit.lib.BranchTrackingStatus 11 | 12 | /** 13 | * Gets the tracking status of a branch. Returns a {@link BranchStatus}. 14 | * 15 | *
16 |  * def status = grgit.branch.status(name: 'the-branch')
17 |  * 
18 | * 19 | * @since 0.2.0 20 | */ 21 | @Operation('status') 22 | class BranchStatusOp implements Callable { 23 | private final Repository repo 24 | 25 | /** 26 | * The branch to get the status of. 27 | * @see {@link ResolveService#toBranch(Object)} 28 | */ 29 | Object name 30 | 31 | BranchStatusOp(Repository repo) { 32 | this.repo = repo 33 | } 34 | 35 | BranchStatus call() { 36 | Branch realBranch = new ResolveService(repo).toBranch(name) 37 | if (realBranch.trackingBranch) { 38 | BranchTrackingStatus status = BranchTrackingStatus.of(repo.jgit.repository, realBranch.fullName) 39 | if (status) { 40 | return new BranchStatus(realBranch, status.aheadCount, status.behindCount) 41 | } else { 42 | throw new IllegalStateException("Could not retrieve status for ${name}") 43 | } 44 | } else { 45 | throw new IllegalStateException("${name} is not set to track another branch") 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/CheckoutOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.ajoberstar.grgit.service.ResolveService 8 | import org.eclipse.jgit.api.CheckoutCommand 9 | 10 | /** 11 | * Checks out a branch to the working tree. Does not support checking out 12 | * specific paths. 13 | * @since 0.1.0 14 | * @see grgit-checkout 15 | * @see git-checkout Manual Page 16 | */ 17 | @Operation('checkout') 18 | class CheckoutOp implements Callable { 19 | private final Repository repo 20 | 21 | /** 22 | * The branch or commit to checkout. 23 | * @see {@link ResolveService#toBranchName(Object)} 24 | */ 25 | Object branch 26 | 27 | /** 28 | * {@code true} if the branch does not exist and should be created, 29 | * {@code false} (the default) otherwise 30 | */ 31 | boolean createBranch = false 32 | 33 | /** 34 | * If {@code createBranch} or {@code orphan} is {@code true}, start the new branch 35 | * at this commit. 36 | * @see {@link ResolveService#toRevisionString(Object)} 37 | */ 38 | Object startPoint 39 | 40 | /** 41 | * {@code true} if the new branch is to be an orphan, 42 | * {@code false} (the default) otherwise 43 | */ 44 | boolean orphan = false 45 | 46 | CheckoutOp(Repository repo) { 47 | this.repo = repo 48 | } 49 | 50 | Void call() { 51 | if (startPoint && !createBranch && !orphan) { 52 | throw new IllegalArgumentException('Cannot set a start point if createBranch and orphan are false.') 53 | } else if ((createBranch || orphan) && !branch) { 54 | throw new IllegalArgumentException('Must specify branch name to create.') 55 | } 56 | CheckoutCommand cmd = repo.jgit.checkout() 57 | ResolveService resolve = new ResolveService(repo) 58 | if (branch) { cmd.name = resolve.toBranchName(branch) } 59 | cmd.createBranch = createBranch 60 | cmd.startPoint = resolve.toRevisionString(startPoint) 61 | cmd.orphan = orphan 62 | cmd.call() 63 | return null 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/CleanOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.eclipse.jgit.api.CleanCommand 8 | 9 | /** 10 | * Remove untracked files from the working tree. Returns the list of 11 | * file paths deleted. 12 | * @since 0.2.0 13 | * @see grgit-clean 14 | * @see git-clean Manual Page 15 | */ 16 | @Operation('clean') 17 | class CleanOp implements Callable> { 18 | private final Repository repo 19 | 20 | /** 21 | * The paths to clean. {@code null} if all paths should be included. 22 | */ 23 | Set paths 24 | 25 | /** 26 | * {@code true} if untracked directories should also be deleted, 27 | * {@code false} (the default) otherwise 28 | */ 29 | boolean directories = false 30 | 31 | /** 32 | * {@code true} if the files should be returned, but not deleted, 33 | * {@code false} (the default) otherwise 34 | */ 35 | boolean dryRun = false 36 | 37 | /** 38 | * {@code false} if files ignored by {@code .gitignore} should 39 | * also be deleted, {@code true} (the default) otherwise 40 | */ 41 | boolean ignore = true 42 | 43 | CleanOp(Repository repo) { 44 | this.repo = repo 45 | } 46 | 47 | Set call() { 48 | CleanCommand cmd = repo.jgit.clean() 49 | if (paths) { cmd.paths = paths } 50 | cmd.cleanDirectories = directories 51 | cmd.dryRun = dryRun 52 | cmd.ignore = ignore 53 | 54 | return cmd.call() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/CloneOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Credentials 6 | import org.ajoberstar.grgit.Grgit 7 | import org.ajoberstar.grgit.Repository 8 | import org.ajoberstar.grgit.auth.TransportOpUtil 9 | import org.ajoberstar.grgit.internal.Operation 10 | import org.ajoberstar.grgit.util.CoercionUtil 11 | import org.eclipse.jgit.api.CloneCommand 12 | import org.eclipse.jgit.api.Git 13 | 14 | /** 15 | * Clones an existing repository. Returns a {@link Grgit} pointing 16 | * to the resulting repository. 17 | * @since 0.1.0 18 | * @see grgit-clone 19 | * @see git-clone Manual Reference. 20 | */ 21 | @Operation('clone') 22 | class CloneOp implements Callable { 23 | /** 24 | * The directory to put the cloned repository. 25 | * @see {@link CoercionUtil#toFile(Object)} 26 | */ 27 | Object dir 28 | 29 | /** 30 | * The URI to the repository to be cloned. 31 | */ 32 | String uri 33 | 34 | /** 35 | * The name of the remote for the upstream repository. Defaults 36 | * to {@code origin}. 37 | */ 38 | String remote = 'origin' 39 | 40 | /** 41 | * {@code true} when all branches have to be fetched, 42 | * {@code false} (the default) otherwise. 43 | */ 44 | boolean all = false 45 | 46 | /** 47 | * {@code true} if the resulting repository should be bare, 48 | * {@code false} (the default) otherwise. 49 | */ 50 | boolean bare = false 51 | 52 | /** 53 | * The list of full refs to be cloned when {@code all = false}. Defaults to 54 | * all available branches. 55 | */ 56 | List branches = [] 57 | 58 | /** 59 | * {@code true} (the default) if a working tree should be checked out, 60 | * {@code false} otherwise 61 | */ 62 | boolean checkout = true 63 | 64 | /** 65 | * The remote ref that should be checked out after the repository is 66 | * cloned. Defaults to {@code master}. 67 | */ 68 | String refToCheckout 69 | 70 | /** 71 | * The depth of the clone. Defaults to full history. 72 | */ 73 | Integer depth = null 74 | 75 | /** 76 | * The username and credentials to use when checking out the 77 | * repository and for subsequent remote operations on the 78 | * repository. This is only needed if hardcoded credentials 79 | * should be used. 80 | * @see {@link org.ajoberstar.grgit.auth.AuthConfig} 81 | */ 82 | Credentials credentials 83 | 84 | Grgit call() { 85 | if (!checkout && refToCheckout) { 86 | throw new IllegalArgumentException('Cannot specify a refToCheckout and set checkout to false.') 87 | } 88 | 89 | CloneCommand cmd = Git.cloneRepository() 90 | TransportOpUtil.configure(cmd, credentials) 91 | 92 | cmd.directory = CoercionUtil.toFile(dir) 93 | cmd.setURI(uri) 94 | cmd.remote = remote 95 | cmd.bare = bare 96 | cmd.noCheckout = !checkout 97 | if (depth != null) { 98 | cmd.depth = depth 99 | } 100 | if (refToCheckout) { cmd.branch = refToCheckout } 101 | if (all) { cmd.cloneAllBranches = all } 102 | if (!branches.isEmpty()) cmd.branchesToClone = branches 103 | 104 | Git jgit = cmd.call() 105 | Repository repo = new Repository(CoercionUtil.toFile(dir), jgit, credentials) 106 | return new Grgit(repo) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/CommitOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Commit 6 | import org.ajoberstar.grgit.Person 7 | import org.ajoberstar.grgit.Repository 8 | import org.ajoberstar.grgit.internal.Operation 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.api.CommitCommand 11 | import org.eclipse.jgit.lib.PersonIdent 12 | import org.eclipse.jgit.revwalk.RevCommit 13 | 14 | /** 15 | * Commits staged changes to the repository. Returns the new {@code Commit}. 16 | * @since 0.1.0 17 | * @see grgit-commit 18 | * @see git-commit Manual Reference. 19 | */ 20 | @Operation('commit') 21 | class CommitOp implements Callable { 22 | private final Repository repo 23 | 24 | /** 25 | * Commit message. 26 | */ 27 | String message 28 | 29 | /** 30 | * Comment to put in the reflog. 31 | */ 32 | String reflogComment 33 | 34 | /** 35 | * The person who committed the changes. Uses the git-config 36 | * setting, if {@code null}. 37 | */ 38 | Person committer 39 | 40 | /** 41 | * The person who authored the changes. Uses the git-config 42 | * setting, if {@code null}. 43 | */ 44 | Person author 45 | 46 | /** 47 | * Only include these paths when committing. {@code null} to 48 | * include all staged changes. 49 | */ 50 | Set paths = [] 51 | 52 | /** 53 | * Commit changes to all previously tracked files, even if 54 | * they aren't staged, if {@code true}. 55 | */ 56 | boolean all = false 57 | 58 | /** 59 | * {@code true} if the previous commit should be amended with 60 | * these changes. 61 | */ 62 | boolean amend = false 63 | 64 | /** 65 | * {@code true} to sign, {@code false} to not sign, and 66 | * {@code null} for default behavior (read from configuration). 67 | */ 68 | Boolean sign 69 | 70 | CommitOp(Repository repo) { 71 | this.repo = repo 72 | } 73 | 74 | Commit call() { 75 | CommitCommand cmd = repo.jgit.commit() 76 | cmd.message = message 77 | cmd.reflogComment = reflogComment 78 | if (committer) { cmd.committer = new PersonIdent(committer.name, committer.email) } 79 | if (author) { cmd.author = new PersonIdent(author.name, author.email) } 80 | paths.each { cmd.setOnly(it) } 81 | if (all) { cmd.all = all } 82 | cmd.amend = amend 83 | cmd.sign = sign 84 | RevCommit commit = cmd.call() 85 | return JGitUtil.convertCommit(repo, commit) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/DescribeOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.ajoberstar.grgit.service.ResolveService 8 | import org.eclipse.jgit.api.DescribeCommand 9 | 10 | /** 11 | * Find the nearest tag reachable. Returns an {@link String}}. 12 | * @see grgit-describe 13 | * @see git-describe Manual Page 14 | */ 15 | @Operation('describe') 16 | class DescribeOp implements Callable { 17 | private final Repository repo 18 | 19 | DescribeOp(Repository repo){ 20 | this.repo = repo 21 | } 22 | 23 | /** 24 | * Sets the commit to be described. Defaults to HEAD. 25 | * @see {@link ResolveService#toRevisionString(Object)} 26 | */ 27 | Object commit 28 | 29 | /** 30 | * Whether to show a uniquely abbreviated commit if no tags match. 31 | */ 32 | boolean always 33 | 34 | /** 35 | * Whether to always use long output format or not. 36 | */ 37 | boolean longDescr 38 | 39 | /** 40 | * Include non-annotated tags when determining nearest tag. 41 | */ 42 | boolean tags 43 | 44 | /** 45 | * glob patterns to match tags against before they are considered 46 | */ 47 | List match = [] 48 | 49 | /** 50 | * Abbreviate resulting object name to use at least n hexadecimal digits 51 | */ 52 | Integer abbrev 53 | 54 | String call(){ 55 | DescribeCommand cmd = repo.jgit.describe() 56 | if (commit) { 57 | cmd.setTarget(new ResolveService(repo).toRevisionString(commit)) 58 | } 59 | cmd.setAlways(always) 60 | cmd.setLong(longDescr) 61 | cmd.setTags(tags) 62 | if (match) { 63 | cmd.setMatch(match as String[]) 64 | } 65 | if(abbrev != null) { 66 | cmd.setAbbrev(abbrev) 67 | } 68 | return cmd.call() 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/FetchOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.auth.TransportOpUtil 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.eclipse.jgit.api.FetchCommand 9 | import org.eclipse.jgit.transport.RefSpec 10 | import org.eclipse.jgit.transport.TagOpt 11 | 12 | /** 13 | * Fetch changes from remotes. 14 | * @since 0.2.0 15 | * @see grgit-fetch 16 | * @see git-fetch Manual Reference. 17 | */ 18 | @Operation('fetch') 19 | class FetchOp implements Callable { 20 | private final Repository repo 21 | 22 | /** 23 | * Which remote should be fetched. 24 | */ 25 | String remote 26 | 27 | /** 28 | * List of refspecs to fetch. 29 | */ 30 | List refSpecs = [] 31 | 32 | /** 33 | * {@code true} if branches removed by the remote should be 34 | * removed locally. 35 | */ 36 | boolean prune = false 37 | 38 | /** 39 | * The depth of the clone. Defaults to full history. 40 | */ 41 | Integer depth = null 42 | 43 | /** 44 | * How should tags be handled. 45 | */ 46 | TagMode tagMode = TagMode.AUTO 47 | 48 | FetchOp(Repository repo) { 49 | this.repo = repo 50 | } 51 | 52 | /** 53 | * Provides a string conversion to the enums. 54 | */ 55 | void setTagMode(String mode) { 56 | tagMode = mode.toUpperCase() 57 | } 58 | 59 | Void call() { 60 | FetchCommand cmd = repo.jgit.fetch() 61 | TransportOpUtil.configure(cmd, repo.credentials) 62 | if (remote) { cmd.remote = remote } 63 | cmd.refSpecs = refSpecs.collect { new RefSpec(it) } 64 | cmd.removeDeletedRefs = prune 65 | cmd.tagOpt = tagMode.jgit 66 | if (depth) { cmd.depth = depth } 67 | cmd.call() 68 | return null 69 | } 70 | 71 | enum TagMode { 72 | AUTO(TagOpt.AUTO_FOLLOW), 73 | ALL(TagOpt.FETCH_TAGS), 74 | NONE(TagOpt.NO_TAGS) 75 | 76 | final TagOpt jgit 77 | 78 | private TagMode(TagOpt opt) { 79 | this.jgit = opt 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/InitOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Grgit 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.util.CoercionUtil 9 | import org.eclipse.jgit.api.Git 10 | import org.eclipse.jgit.api.InitCommand 11 | 12 | /** 13 | * Initializes a new repository. Returns a {@link Grgit} pointing 14 | * to the resulting repository. 15 | * @since 0.1.0 16 | * @see grgit-init 17 | * @see git-init Manual Reference. 18 | */ 19 | @Operation('init') 20 | class InitOp implements Callable { 21 | /** 22 | * {@code true} if the repository should not have a 23 | * working tree, {@code false} (the default) otherwise 24 | */ 25 | boolean bare = false 26 | 27 | /** 28 | * The directory to initialize the repository in. 29 | * @see {@link CoercionUtil#toFile(Object)} 30 | */ 31 | Object dir 32 | 33 | Grgit call() { 34 | InitCommand cmd = Git.init() 35 | cmd.bare = bare 36 | cmd.directory = CoercionUtil.toFile(dir) 37 | Git jgit = cmd.call() 38 | Repository repo = new Repository(CoercionUtil.toFile(dir), jgit, null) 39 | return new Grgit(repo) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/LogOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Commit 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.service.ResolveService 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.api.LogCommand 11 | 12 | /** 13 | * Gets a log of commits in the repository. Returns a list of {@link Commit}s. 14 | * Since a Git history is not necessarilly a line, these commits may not be in 15 | * a strict order. 16 | * @since 0.1.0 17 | * @see grgit-log 18 | * @see git-log Manual Page 19 | */ 20 | @Operation('log') 21 | class LogOp implements Callable> { 22 | private final Repository repo 23 | 24 | /** 25 | * @see {@link ResolveService#toRevisionString(Object)} 26 | */ 27 | List includes = [] 28 | /** 29 | * @see {@link ResolveService#toRevisionString(Object)} 30 | */ 31 | List excludes = [] 32 | List paths = [] 33 | int skipCommits = -1 34 | int maxCommits = -1 35 | 36 | LogOp(Repository repo) { 37 | this.repo = repo 38 | } 39 | 40 | void range(Object since, Object until) { 41 | excludes << since 42 | includes << until 43 | } 44 | 45 | List call() { 46 | LogCommand cmd = repo.jgit.log() 47 | ResolveService resolve = new ResolveService(repo) 48 | def toObjectId = { rev -> 49 | String revstr = resolve.toRevisionString(rev) 50 | def id = JGitUtil.resolveRevObject(repo, revstr, true) 51 | if (id) { 52 | return id 53 | } else { 54 | throw new IllegalArgumentException("\"${revstr}\" cannot be resolved to an object in this repository.") 55 | } 56 | } 57 | 58 | includes.collect(toObjectId).each { object -> 59 | cmd.add(object) 60 | } 61 | excludes.collect(toObjectId).each { object -> 62 | cmd.not(object) 63 | } 64 | paths.each { path -> 65 | cmd.addPath(path) 66 | } 67 | cmd.skip = skipCommits 68 | cmd.maxCount = maxCommits 69 | return cmd.call().collect { JGitUtil.convertCommit(repo, it) }.asImmutable() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/LsRemoteOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Ref 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.auth.TransportOpUtil 8 | import org.ajoberstar.grgit.internal.Operation 9 | import org.eclipse.jgit.api.LsRemoteCommand 10 | import org.eclipse.jgit.lib.ObjectId 11 | 12 | /** 13 | * List references in a remote repository. 14 | * @since 2.0.0 15 | * @see grgit-lsremote 16 | * @see git-ls-remote Manual Page 17 | */ 18 | @Operation('lsremote') 19 | class LsRemoteOp implements Callable> { 20 | private final Repository repo 21 | 22 | String remote = 'origin' 23 | 24 | boolean heads = false 25 | 26 | boolean tags = false 27 | 28 | LsRemoteOp(Repository repo) { 29 | this.repo = repo 30 | } 31 | 32 | Map call() { 33 | LsRemoteCommand cmd = repo.jgit.lsRemote() 34 | TransportOpUtil.configure(cmd, repo.credentials) 35 | cmd.remote = remote 36 | cmd.heads = heads 37 | cmd.tags = tags 38 | return cmd.call().collectEntries { jgitRef -> 39 | Ref ref = new Ref(jgitRef.getName()) 40 | [(ref): ObjectId.toString(jgitRef.getObjectId())] 41 | }.asImmutable() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/OpenOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Credentials 6 | import org.ajoberstar.grgit.Grgit 7 | import org.ajoberstar.grgit.Repository 8 | import org.ajoberstar.grgit.internal.Operation 9 | import org.ajoberstar.grgit.util.CoercionUtil 10 | import org.eclipse.jgit.api.Git 11 | import org.eclipse.jgit.internal.storage.file.FileRepository 12 | import org.eclipse.jgit.storage.file.FileRepositoryBuilder 13 | 14 | /** 15 | * Opens an existing repository. Returns a {@link Grgit} pointing 16 | * to the resulting repository. 17 | * @since 1.0.0 18 | * @see grgit-open 19 | */ 20 | @Operation('open') 21 | class OpenOp implements Callable { 22 | /** 23 | * Hardcoded credentials to use for remote operations. 24 | */ 25 | Credentials credentials 26 | 27 | /** 28 | * The directory to open the repository from. Incompatible 29 | * with {@code currentDir}. 30 | * @see {@link CoercionUtil#toFile(Object)} 31 | */ 32 | Object dir 33 | 34 | /** 35 | * The directory to begin searching from the repository 36 | * from. Incompatible with {@code dir}. 37 | * @see {@link CoercionUtil#toFile(Object)} 38 | */ 39 | Object currentDir 40 | 41 | Grgit call() { 42 | if (dir && currentDir) { 43 | throw new IllegalArgumentException('Cannot use both dir and currentDir.') 44 | } else if (dir) { 45 | def dirFile = CoercionUtil.toFile(dir) 46 | def repo = new Repository(dirFile, Git.open(dirFile), credentials) 47 | return new Grgit(repo) 48 | } else { 49 | FileRepositoryBuilder builder = new FileRepositoryBuilder() 50 | builder.readEnvironment() 51 | if (currentDir) { 52 | File currentDirFile = CoercionUtil.toFile(currentDir) 53 | builder.findGitDir(currentDirFile) 54 | } else { 55 | builder.findGitDir() 56 | } 57 | 58 | if(builder.getGitDir() == null){ 59 | throw new IllegalStateException('No .git directory found!'); 60 | } 61 | 62 | FileRepository jgitRepo = builder.build() 63 | Git jgit = new Git(jgitRepo) 64 | Repository repo = new Repository(jgitRepo.directory, jgit, credentials) 65 | return new Grgit(repo) 66 | } 67 | } 68 | 69 | @Deprecated 70 | Credentials getCreds(){ 71 | return credentials 72 | } 73 | 74 | @Deprecated 75 | void setCreds(Credentials creds){ 76 | this.credentials = creds 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/PullOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.auth.TransportOpUtil 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.eclipse.jgit.api.PullCommand 9 | import org.eclipse.jgit.api.PullResult 10 | 11 | /** 12 | * Pulls changes from the remote on the current branch. If the changes 13 | * conflict, the pull will fail, any conflicts can be retrieved with 14 | * {@code grgit.status()}, and throwing an exception. 15 | * @since 0.2.0 16 | * @see grgit-pull 17 | * @see git-pull Manual Page 18 | */ 19 | @Operation('pull') 20 | class PullOp implements Callable { 21 | private final Repository repo 22 | 23 | /** 24 | * The name of the remote to pull. If not set, the current branch's 25 | * configuration will be used. 26 | */ 27 | String remote 28 | 29 | /** 30 | * The name of the remote branch to pull. If not set, the current branch's 31 | * configuration will be used. 32 | */ 33 | String branch 34 | 35 | /** 36 | * Rebase on top of the changes when they are pulled in, if 37 | * {@code true}. {@code false} (the default) otherwise. 38 | */ 39 | boolean rebase = false 40 | 41 | PullOp(Repository repo) { 42 | this.repo = repo 43 | } 44 | 45 | Void call() { 46 | PullCommand cmd = repo.jgit.pull() 47 | if (remote) { cmd.remote = remote } 48 | if (branch) { cmd.remoteBranchName = branch } 49 | cmd.rebase = rebase 50 | TransportOpUtil.configure(cmd, repo.credentials) 51 | 52 | PullResult result = cmd.call() 53 | if (!result.successful) { 54 | throw new IllegalStateException("Could not pull: ${result}") 55 | } 56 | return null 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/PushOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.PushException 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.auth.TransportOpUtil 8 | import org.ajoberstar.grgit.internal.Operation 9 | import org.eclipse.jgit.api.PushCommand 10 | import org.eclipse.jgit.transport.RemoteRefUpdate 11 | 12 | /** 13 | * Push changes to a remote repository. 14 | * @since 0.1.0 15 | * @see grgit-push 16 | * @see git-push Manual Page 17 | */ 18 | @Operation('push') 19 | class PushOp implements Callable { 20 | private final Repository repo 21 | 22 | /** 23 | * The remote to push to. 24 | */ 25 | String remote 26 | 27 | /** 28 | * The refs or refspecs to use when pushing. If {@code null} 29 | * and {@code all} is {@code false} only push the current branch. 30 | */ 31 | List refsOrSpecs = [] 32 | 33 | /** 34 | * {@code true} to push all branches, {@code false} (the default) 35 | * to only push the current one. 36 | */ 37 | boolean all = false 38 | 39 | /** 40 | * {@code true} to push tags, {@code false} (the default) otherwise. 41 | */ 42 | boolean tags = false 43 | 44 | /** 45 | * {@code true} if branches should be pushed even if they aren't 46 | * a fast-forward, {@code false} (the default) if it should fail. 47 | */ 48 | boolean force = false 49 | 50 | /** 51 | * {@code true} if result of this operation should be just estimation 52 | * of real operation result, no real push is performed. 53 | * {@code false} (the default) if real push to remote repo should be performed. 54 | * 55 | * @since 0.4.1 56 | */ 57 | boolean dryRun = false 58 | 59 | /** 60 | * The push options to send to the receiving remote 61 | */ 62 | List pushOptions = [] 63 | 64 | PushOp(Repository repo) { 65 | this.repo = repo 66 | } 67 | 68 | Void call() { 69 | PushCommand cmd = repo.jgit.push() 70 | TransportOpUtil.configure(cmd, repo.credentials) 71 | if (remote) { cmd.remote = remote } 72 | refsOrSpecs.each { cmd.add(it) } 73 | if (all) { cmd.setPushAll() } 74 | if (tags) { cmd.setPushTags() } 75 | cmd.force = force 76 | cmd.dryRun = dryRun 77 | if (pushOptions) { 78 | cmd.pushOptions = pushOptions 79 | } 80 | 81 | def failures = [] 82 | cmd.call().each { result -> 83 | result.remoteUpdates.findAll { update -> 84 | !(update.status == RemoteRefUpdate.Status.OK || update.status == RemoteRefUpdate.Status.UP_TO_DATE) 85 | }.each { update -> 86 | String info = "${update.srcRef} to ${update.remoteName}" 87 | String message = update.message ? " (${update.message})" : '' 88 | failures << "${info}${message}" 89 | } 90 | } 91 | if (failures) { 92 | throw new PushException("Failed to push: ${failures.join(',')}") 93 | } 94 | return null 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/RemoteAddOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Remote 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.util.JGitUtil 9 | import org.eclipse.jgit.lib.Config 10 | import org.eclipse.jgit.transport.RefSpec 11 | import org.eclipse.jgit.transport.RemoteConfig 12 | import org.eclipse.jgit.transport.URIish 13 | 14 | /** 15 | * Adds a remote to the repository. Returns the newly created {@link org.ajoberstar.grgit.Remote}. 16 | * If remote with given name already exists, this command will fail. 17 | * @see grgit-remote 18 | * @see git-remote Manual Page 19 | */ 20 | @Operation('add') 21 | class RemoteAddOp implements Callable { 22 | 23 | private final Repository repository 24 | 25 | /** 26 | * Name of the remote. 27 | */ 28 | String name 29 | 30 | /** 31 | * URL to fetch from. 32 | */ 33 | String url 34 | 35 | /** 36 | * URL to push to. 37 | */ 38 | String pushUrl 39 | 40 | /** 41 | * Specs to fetch from the remote. 42 | */ 43 | List fetchRefSpecs = [] 44 | 45 | /** 46 | * Specs to push to the remote. 47 | */ 48 | List pushRefSpecs = [] 49 | 50 | /** 51 | * Whether or not pushes will mirror the repository. 52 | */ 53 | boolean mirror 54 | 55 | RemoteAddOp(Repository repo) { 56 | this.repository = repo 57 | } 58 | 59 | @Override 60 | Remote call() { 61 | Config config = repository.jgit.repository.config 62 | if (RemoteConfig.getAllRemoteConfigs(config).find { it.name == name }) { 63 | throw new IllegalStateException("Remote $name already exists.") 64 | } 65 | def toUri = { url -> new URIish(url) } 66 | def toRefSpec = { spec -> new RefSpec(spec) } 67 | RemoteConfig remote = new RemoteConfig(config, name) 68 | if (url) { remote.addURI(toUri(url)) } 69 | if (pushUrl) { remote.addPushURI(toUri(pushUrl)) } 70 | remote.fetchRefSpecs = (fetchRefSpecs ?: ["+refs/heads/*:refs/remotes/$name/*"]).collect(toRefSpec) 71 | remote.pushRefSpecs = pushRefSpecs.collect(toRefSpec) 72 | remote.mirror = mirror 73 | remote.update(config) 74 | config.save() 75 | return JGitUtil.convertRemote(remote) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/RemoteListOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.Remote 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.util.JGitUtil 9 | import org.eclipse.jgit.transport.RemoteConfig 10 | 11 | /** 12 | * Lists remotes in the repository. Returns a list of {@link org.ajoberstar.grgit.Remote}. 13 | * @see grgit-remote 14 | * @see git-remote Manual Page 15 | */ 16 | @Operation('list') 17 | class RemoteListOp implements Callable> { 18 | private final Repository repository 19 | 20 | RemoteListOp(Repository repo) { 21 | this.repository = repo 22 | } 23 | 24 | @Override 25 | List call() { 26 | return RemoteConfig.getAllRemoteConfigs(repository.jgit.repository.config).collect { rc -> 27 | if (rc.uris.size() > 1 || rc.pushURIs.size() > 1) { 28 | throw new IllegalArgumentException("Grgit does not currently support multiple URLs in remote: [uris: ${rc.uris}, pushURIs:${rc.pushURIs}]") 29 | } 30 | JGitUtil.convertRemote(rc) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/RemoteRemoveOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.eclipse.jgit.lib.Config 8 | 9 | /** 10 | * Removes a remote from the repository. 11 | * @see grgit-remote 12 | * @see git-remote Manual Page 13 | */ 14 | @Operation('remove') 15 | class RemoteRemoveOp implements Callable { 16 | 17 | private final Repository repository 18 | 19 | /** 20 | * Name of the remote. 21 | */ 22 | String name 23 | 24 | RemoteRemoveOp(Repository repo) { 25 | this.repository = repo 26 | } 27 | 28 | @Override 29 | Void call() { 30 | Config config = repository.jgit.repository.config 31 | config.unsetSection("remote", name) 32 | config.save(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/ResetOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.ajoberstar.grgit.service.ResolveService 8 | import org.eclipse.jgit.api.ResetCommand 9 | 10 | /** 11 | * Reset changes in the repository. 12 | * @since 0.1.0 13 | * @see grgit-reset 14 | * @see git-reset Manual Page 15 | */ 16 | @Operation('reset') 17 | class ResetOp implements Callable { 18 | private final Repository repo 19 | 20 | /** 21 | * The paths to reset. 22 | */ 23 | Set paths = [] 24 | 25 | /** 26 | * The commit to reset back to. Defaults to HEAD. 27 | * @see {@link ResolveService#toRevisionString(Object)} 28 | */ 29 | Object commit 30 | 31 | /** 32 | * The mode to use when resetting. 33 | */ 34 | Mode mode = Mode.MIXED 35 | 36 | ResetOp(Repository repo) { 37 | this.repo = repo 38 | } 39 | 40 | void setMode(String mode) { 41 | this.mode = mode.toUpperCase() 42 | } 43 | 44 | Void call() { 45 | if (!paths.empty && mode != Mode.MIXED) { 46 | throw new IllegalStateException('Cannot set mode when resetting paths.') 47 | } 48 | 49 | ResetCommand cmd = repo.jgit.reset() 50 | paths.each { cmd.addPath(it) } 51 | if (commit) { 52 | cmd.ref = new ResolveService(repo).toRevisionString(commit) 53 | } 54 | if (paths.empty) { 55 | cmd.mode = mode.jgit 56 | } 57 | 58 | cmd.call() 59 | return null 60 | } 61 | 62 | static enum Mode { 63 | /** 64 | * Reset the index and working tree. 65 | */ 66 | HARD(ResetCommand.ResetType.HARD), 67 | /** 68 | * Reset the index, but not the working tree. 69 | */ 70 | MIXED(ResetCommand.ResetType.MIXED), 71 | /** 72 | * Only reset the HEAD. Leave the index and working tree as-is. 73 | */ 74 | SOFT(ResetCommand.ResetType.SOFT) 75 | 76 | private final ResetCommand.ResetType jgit 77 | 78 | private Mode(ResetCommand.ResetType jgit) { 79 | this.jgit = jgit 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/RevertOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Commit 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.service.ResolveService 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.api.RevertCommand 11 | import org.eclipse.jgit.revwalk.RevCommit 12 | 13 | /** 14 | * Revert one or more commits. Returns the new HEAD {@link Commit}. 15 | * @since 0.1.0 16 | * @see grgit-revert 17 | * @see git-revert Manual Page 18 | */ 19 | @Operation('revert') 20 | class RevertOp implements Callable { 21 | private final Repository repo 22 | 23 | /** 24 | * List of commits to revert. 25 | * @see {@link ResolveService#toRevisionString(Object)} 26 | */ 27 | List commits = [] 28 | 29 | RevertOp(Repository repo) { 30 | this.repo = repo 31 | } 32 | 33 | Commit call() { 34 | RevertCommand cmd = repo.jgit.revert() 35 | commits.each { 36 | String revstr = new ResolveService(repo).toRevisionString(it) 37 | cmd.include(JGitUtil.resolveObject(repo, revstr)) 38 | } 39 | RevCommit commit = cmd.call() 40 | if (cmd.failingResult) { 41 | throw new IllegalStateException("Could not merge reverted commits (conflicting files can be retrieved with a call to grgit.status()): ${cmd.failingResult}") 42 | } 43 | return JGitUtil.convertCommit(repo, commit) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/RmOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.eclipse.jgit.api.RmCommand 8 | 9 | /** 10 | * Remove files from the index and (optionally) delete them from the working tree. 11 | * Note that wildcards are not supported. 12 | * @since 0.1.0 13 | * @see grgit-remove 14 | * @see git-rm Manual Page 15 | */ 16 | @Operation('remove') 17 | class RmOp implements Callable { 18 | private final Repository repo 19 | 20 | /** 21 | * The file patterns to remove. 22 | */ 23 | Set patterns = [] 24 | 25 | /** 26 | * {@code true} if files should only be removed from the index, 27 | * {@code false} (the default) otherwise. 28 | */ 29 | boolean cached = false 30 | 31 | RmOp(Repository repo) { 32 | this.repo = repo 33 | } 34 | 35 | Void call() { 36 | RmCommand cmd = repo.jgit.rm() 37 | patterns.each { cmd.addFilepattern(it) } 38 | cmd.cached = cached 39 | cmd.call() 40 | return null 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/ShowOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.CommitDiff 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.service.ResolveService 9 | import org.ajoberstar.grgit.util.JGitUtil 10 | import org.eclipse.jgit.diff.DiffEntry 11 | import org.eclipse.jgit.diff.RenameDetector 12 | import org.eclipse.jgit.diff.DiffEntry.ChangeType 13 | import org.eclipse.jgit.treewalk.TreeWalk 14 | 15 | /** 16 | * Show changes made in a commit. 17 | * Returns changes made in commit in the form of {@link org.ajoberstar.grgit.CommitDiff}. 18 | * @since 1.2.0 19 | * @see grgit-show 20 | * @see git-show Manual Page 21 | */ 22 | @Operation('show') 23 | class ShowOp implements Callable { 24 | private final Repository repo 25 | 26 | /** 27 | * The commit to show 28 | * @see {@link org.ajoberstar.grgit.service.ResolveService#toRevisionString(Object)} 29 | */ 30 | Object commit 31 | 32 | ShowOp(Repository repo) { 33 | this.repo = repo 34 | } 35 | 36 | CommitDiff call() { 37 | if (!commit) { 38 | throw new IllegalArgumentException('You must specify which commit to show') 39 | } 40 | def revString = new ResolveService(repo).toRevisionString(commit) 41 | def commitId = JGitUtil.resolveRevObject(repo, revString) 42 | def parentId = JGitUtil.resolveParents(repo, commitId).find() 43 | 44 | def commit = JGitUtil.resolveCommit(repo, commitId) 45 | 46 | TreeWalk walk = new TreeWalk(repo.jgit.repository) 47 | walk.recursive = true 48 | 49 | if (parentId) { 50 | walk.addTree(parentId.tree) 51 | walk.addTree(commitId.tree) 52 | List initialEntries = DiffEntry.scan(walk) 53 | RenameDetector detector = new RenameDetector(repo.jgit.repository) 54 | detector.addAll(initialEntries) 55 | List entries = detector.compute() 56 | Map entriesByType = entries.groupBy { it.changeType } 57 | 58 | return new CommitDiff( 59 | commit: commit, 60 | added: entriesByType[ChangeType.ADD].collect { it.newPath }, 61 | copied: entriesByType[ChangeType.COPY].collect { it.newPath }, 62 | modified: entriesByType[ChangeType.MODIFY].collect { it.newPath }, 63 | removed: entriesByType[ChangeType.DELETE].collect { it.oldPath }, 64 | renamed: entriesByType[ChangeType.RENAME].collect { it.newPath }, 65 | renamings: entriesByType[ChangeType.RENAME]?.collectEntries { [(it.oldPath): it.newPath] } ?: [:] 66 | ) 67 | } else { 68 | walk.addTree(commitId.tree) 69 | def added = [] 70 | while (walk.next()) { 71 | added << walk.pathString 72 | } 73 | return new CommitDiff( 74 | commit: commit, 75 | added: added 76 | ) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/StatusOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.Status 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.util.JGitUtil 9 | import org.eclipse.jgit.api.StatusCommand 10 | 11 | /** 12 | * Gets the current status of the repository. Returns an {@link Status}. 13 | * @since 0.1.0 14 | * @see grgit-status 15 | * @see git-status Manual Page 16 | */ 17 | @Operation('status') 18 | class StatusOp implements Callable { 19 | private final Repository repo 20 | 21 | StatusOp(Repository repo) { 22 | this.repo = repo 23 | } 24 | 25 | Status call() { 26 | StatusCommand cmd = repo.jgit.status() 27 | return JGitUtil.convertStatus(cmd.call()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/TagAddOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Person 6 | import org.ajoberstar.grgit.Repository 7 | import org.ajoberstar.grgit.Tag 8 | import org.ajoberstar.grgit.internal.Operation 9 | import org.ajoberstar.grgit.service.ResolveService 10 | import org.ajoberstar.grgit.util.JGitUtil 11 | import org.eclipse.jgit.api.TagCommand 12 | import org.eclipse.jgit.lib.PersonIdent 13 | import org.eclipse.jgit.lib.Ref 14 | 15 | /** 16 | * Adds a tag to the repository. Returns the newly created {@link Tag}. 17 | * @since 0.2.0 18 | * @see grgit-tag 19 | * @see git-tag Manual Page 20 | */ 21 | @Operation('add') 22 | class TagAddOp implements Callable { 23 | private final Repository repo 24 | 25 | /** 26 | * The name of the tag to create. 27 | */ 28 | String name 29 | 30 | /** 31 | * The message to put on the tag. 32 | */ 33 | String message 34 | 35 | /** 36 | * The person who created the tag. 37 | */ 38 | Person tagger 39 | 40 | /** 41 | * {@code true} (the default) if an annotated tag should be 42 | * created, {@code false} otherwise. 43 | */ 44 | boolean annotate = true 45 | 46 | /** 47 | * {@code true} to overwrite an existing tag, {@code false} 48 | * (the default) otherwise 49 | */ 50 | boolean force = false 51 | 52 | /** 53 | * The commit the tag should point to. 54 | * @see {@link ResolveService#toRevisionString(Object)} 55 | */ 56 | Object pointsTo 57 | 58 | TagAddOp(Repository repo) { 59 | this.repo = repo 60 | } 61 | 62 | Tag call() { 63 | TagCommand cmd = repo.jgit.tag() 64 | cmd.name = name 65 | cmd.message = message 66 | if (tagger) { cmd.tagger = new PersonIdent(tagger.name, tagger.email) } 67 | cmd.annotated = annotate 68 | cmd.forceUpdate = force 69 | if (pointsTo) { 70 | def revstr = new ResolveService(repo).toRevisionString(pointsTo) 71 | cmd.objectId = JGitUtil.resolveRevObject(repo, revstr) 72 | } 73 | 74 | Ref ref = cmd.call() 75 | return JGitUtil.resolveTag(repo, ref) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/TagListOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.Tag 7 | import org.ajoberstar.grgit.internal.Operation 8 | import org.ajoberstar.grgit.util.JGitUtil 9 | import org.eclipse.jgit.api.ListTagCommand 10 | 11 | /** 12 | * Lists tags in the repository. Returns a list of {@link Tag}. 13 | * @since 0.2.0 14 | * @see grgit-tag 15 | * @see git-tag Manual Page 16 | */ 17 | @Operation('list') 18 | class TagListOp implements Callable> { 19 | private final Repository repo 20 | 21 | TagListOp(Repository repo) { 22 | this.repo = repo 23 | } 24 | 25 | List call() { 26 | ListTagCommand cmd = repo.jgit.tagList() 27 | 28 | return cmd.call().collect { 29 | JGitUtil.resolveTag(repo, it) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/TagRemoveOp.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Repository 6 | import org.ajoberstar.grgit.internal.Operation 7 | import org.ajoberstar.grgit.service.ResolveService 8 | import org.eclipse.jgit.api.DeleteTagCommand 9 | 10 | /** 11 | * Removes one or more tags from the repository. Returns a list of 12 | * the fully qualified tag names that were removed. 13 | * @since 0.2.0 14 | * @see grgit-tag 15 | * @see git-tag Manual Page 16 | */ 17 | @Operation('remove') 18 | class TagRemoveOp implements Callable> { 19 | private final Repository repo 20 | 21 | /** 22 | * Names of tags to remove. 23 | * @see {@link ResolveService#toTagName(Object)} 24 | */ 25 | List names = [] 26 | 27 | TagRemoveOp(Repository repo) { 28 | this.repo = repo 29 | } 30 | 31 | List call() { 32 | DeleteTagCommand cmd = repo.jgit.tagDelete() 33 | cmd.tags = names.collect { new ResolveService(repo).toTagName(it) } 34 | 35 | return cmd.call() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/operation/package-info.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/package-info.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/service/BranchService.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.service 2 | 3 | import org.ajoberstar.grgit.Branch 4 | import org.ajoberstar.grgit.Repository 5 | import org.ajoberstar.grgit.internal.WithOperations 6 | import org.ajoberstar.grgit.operation.* 7 | import org.ajoberstar.grgit.util.JGitUtil 8 | import org.eclipse.jgit.lib.Ref 9 | 10 | /** 11 | * Provides support for performing branch-related operations on 12 | * a Git repository. 13 | * 14 | *

15 | * Details of each operation's properties and methods are available on the 16 | * doc page for the class. The following operations are supported directly on 17 | * this service instance. 18 | *

19 | * 20 | *
    21 | *
  • {@link org.ajoberstar.grgit.operation.BranchAddOp add}
  • 22 | *
  • {@link org.ajoberstar.grgit.operation.BranchChangeOp change}
  • 23 | *
  • {@link org.ajoberstar.grgit.operation.BranchListOp list}
  • 24 | *
  • {@link org.ajoberstar.grgit.operation.BranchRemoveOp remove}
  • 25 | *
  • {@link org.ajoberstar.grgit.operation.BranchStatusOp status}
  • 26 | *
27 | * 28 | * @since 0.2.0 29 | * @see grgit-branch 30 | */ 31 | @WithOperations(instanceOperations=[BranchListOp, BranchAddOp, BranchRemoveOp, BranchChangeOp, BranchStatusOp]) 32 | class BranchService { 33 | private final Repository repository 34 | 35 | BranchService(Repository repository) { 36 | this.repository = repository 37 | } 38 | 39 | /** 40 | * Gets the branch associated with the current HEAD. 41 | * @return the branch or {@code null} if the HEAD is detached 42 | */ 43 | Branch current() { 44 | Ref ref = repository.jgit.repository.exactRef('HEAD')?.target 45 | return ref ? JGitUtil.resolveBranch(repository, ref) : null 46 | } 47 | 48 | /** 49 | * Gets the branch associated with the current HEAD. 50 | * @return the branch or {@code null} if the HEAD is detached 51 | * @deprecated Use BranchService#current() 52 | */ 53 | @Deprecated 54 | Branch getCurrent() { 55 | return current() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/service/RemoteService.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.service 2 | 3 | import org.ajoberstar.grgit.Repository 4 | import org.ajoberstar.grgit.internal.WithOperations 5 | import org.ajoberstar.grgit.operation.RemoteAddOp 6 | import org.ajoberstar.grgit.operation.RemoteListOp 7 | import org.ajoberstar.grgit.operation.RemoteRemoveOp 8 | 9 | /** 10 | * Provides support for remote-related operations on a Git repository. 11 | * 12 | *

13 | * Details of each operation's properties and methods are available on the 14 | * doc page for the class. The following operations are supported directly on 15 | * this service instance. 16 | *

17 | * 18 | *
    19 | *
  • {@link org.ajoberstar.grgit.operation.RemoteAddOp add}
  • 20 | *
  • {@link org.ajoberstar.grgit.operation.RemoteListOp list}
  • 21 | *
  • {@link org.ajoberstar.grgit.operation.RemoteRemoveOp remove}
  • 22 | *
23 | */ 24 | @WithOperations(instanceOperations=[RemoteListOp, RemoteAddOp, RemoteRemoveOp]) 25 | class RemoteService { 26 | private final Repository repository 27 | 28 | RemoteService(Repository repository) { 29 | this.repository = repository 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/service/TagService.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.service 2 | 3 | import org.ajoberstar.grgit.Repository 4 | import org.ajoberstar.grgit.internal.WithOperations 5 | import org.ajoberstar.grgit.operation.TagAddOp 6 | import org.ajoberstar.grgit.operation.TagListOp 7 | import org.ajoberstar.grgit.operation.TagRemoveOp 8 | 9 | /** 10 | * Provides support for performing tag-related operations on 11 | * a Git repository. 12 | * 13 | *

14 | * Details of each operation's properties and methods are available on the 15 | * doc page for the class. The following operations are supported directly on 16 | * this service instance. 17 | *

18 | * 19 | *
    20 | *
  • {@link org.ajoberstar.grgit.operation.TagAddOp add}
  • 21 | *
  • {@link org.ajoberstar.grgit.operation.TagListOp list}
  • 22 | *
  • {@link org.ajoberstar.grgit.operation.TagRemoveOp remove}
  • 23 | *
24 | * 25 | * @since 0.2.0 26 | * @see grgit-tag 27 | */ 28 | @WithOperations(instanceOperations=[TagListOp, TagAddOp, TagRemoveOp]) 29 | class TagService { 30 | private final Repository repository 31 | 32 | TagService(Repository repository) { 33 | this.repository = repository 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/service/package-info.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.service 2 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/util/CoercionUtil.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.util 2 | 3 | import java.nio.file.Path 4 | 5 | final class CoercionUtil { 6 | private CoercionUtil() { 7 | throw new AssertionError('Can not instantiate this class.') 8 | } 9 | 10 | static File toFile(Object obj) { 11 | if (obj instanceof File) { 12 | return obj 13 | } else if (obj instanceof Path) { 14 | return obj.toFile() 15 | } else { 16 | return new File(obj.toString()) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /grgit-core/src/main/groovy/org/ajoberstar/grgit/util/package-info.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.util 2 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/auth/AuthConfigSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.auth 2 | 3 | import org.ajoberstar.grgit.Credentials 4 | 5 | import spock.lang.Specification 6 | import spock.lang.Unroll 7 | 8 | class AuthConfigSpec extends Specification { 9 | def 'getHardcodedCreds returns creds if username and password are set with properties'() { 10 | given: 11 | def props = [(AuthConfig.USERNAME_OPTION): 'myuser', (AuthConfig.PASSWORD_OPTION): 'mypass'] 12 | expect: 13 | AuthConfig.fromMap(props).getHardcodedCreds() == new Credentials('myuser', 'mypass') 14 | } 15 | 16 | def 'getHardcodedCreds returns creds if username and password are set with env'() { 17 | given: 18 | def env = [(AuthConfig.USERNAME_ENV_VAR): 'myuser', (AuthConfig.PASSWORD_ENV_VAR): 'mypass'] 19 | expect: 20 | AuthConfig.fromMap([:], env).getHardcodedCreds() == new Credentials('myuser', 'mypass') 21 | } 22 | 23 | def 'getHardcodedCreds returns creds if username is set and password is not'() { 24 | given: 25 | def props = [(AuthConfig.USERNAME_OPTION): 'myuser'] 26 | expect: 27 | AuthConfig.fromMap(props).getHardcodedCreds() == new Credentials('myuser', null) 28 | } 29 | 30 | def 'getHardcodedCreds are not populated if username is not set'() { 31 | expect: 32 | !AuthConfig.fromMap([:]).getHardcodedCreds().isPopulated() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/fixtures/Categories.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.fixtures 2 | 3 | interface PlatformSpecific {} 4 | interface WindowsSpecific extends PlatformSpecific {} 5 | interface LinuxSpecific extends PlatformSpecific {} 6 | interface MacSpecific extends PlatformSpecific {} 7 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/fixtures/GitTestUtil.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.fixtures 2 | 3 | import org.ajoberstar.grgit.Branch 4 | import org.ajoberstar.grgit.Commit 5 | import org.ajoberstar.grgit.Grgit 6 | import org.ajoberstar.grgit.util.JGitUtil 7 | 8 | import org.eclipse.jgit.api.ListBranchCommand.ListMode 9 | import org.eclipse.jgit.transport.RemoteConfig 10 | 11 | final class GitTestUtil { 12 | private GitTestUtil() { 13 | throw new AssertionError('Cannot instantiate this class.') 14 | } 15 | 16 | static File repoFile(Grgit grgit, String path, boolean makeDirs = true) { 17 | def file = new File(grgit.repository.rootDir, path) 18 | if (makeDirs) file.parentFile.mkdirs() 19 | return file 20 | } 21 | 22 | static File repoDir(Grgit grgit, String path) { 23 | def file = new File(grgit.repository.rootDir, path) 24 | file.mkdirs() 25 | return file 26 | } 27 | 28 | static Branch branch(String fullName, String trackingBranchFullName = null) { 29 | Branch trackingBranch = trackingBranchFullName ? branch(trackingBranchFullName) : null 30 | return new Branch(fullName, trackingBranch) 31 | } 32 | 33 | static List branches(Grgit grgit, boolean trim = false) { 34 | return grgit.repository.jgit.branchList().with { 35 | listMode = ListMode.ALL 36 | delegate.call() 37 | }.collect { trim ? it.name - 'refs/heads/' : it.name } 38 | } 39 | 40 | static List remoteBranches(Grgit grgit) { 41 | return grgit.repository.jgit.branchList().with { 42 | listMode = ListMode.REMOTE 43 | delegate.call() 44 | }.collect { it.name - 'refs/remotes/origin/' } 45 | } 46 | 47 | static List tags(Grgit grgit) { 48 | return grgit.repository.jgit.tagList().call().collect { 49 | it.name - 'refs/tags/' 50 | } 51 | } 52 | 53 | static List remotes(Grgit grgit) { 54 | def jgitConfig = grgit.repository.jgit.repo.config 55 | return RemoteConfig.getAllRemoteConfigs(jgitConfig).collect { it.name} 56 | } 57 | 58 | static Commit resolve(Grgit grgit, String revstr) { 59 | return JGitUtil.resolveCommit(grgit.repository, revstr) 60 | } 61 | 62 | static void configure(Grgit grgit, Closure closure) { 63 | def config = grgit.repository.jgit.repo.config 64 | config.with(closure) 65 | config.save() 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/fixtures/MultiGitOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.fixtures 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.Person 5 | 6 | import org.eclipse.jgit.api.Git 7 | 8 | import spock.lang.TempDir 9 | 10 | import spock.lang.Specification 11 | 12 | class MultiGitOpSpec extends Specification { 13 | @TempDir 14 | File tempDir 15 | 16 | Person person = new Person('Bruce Wayne', 'bruce.wayne@wayneindustries.com') 17 | 18 | private List grgits = [] 19 | 20 | def cleanup() { 21 | grgits.each { it.close() } 22 | } 23 | 24 | protected Grgit init(String name) { 25 | File repoDir = new File(tempDir, name).canonicalFile 26 | Git git = Git.init() 27 | .setDirectory(repoDir) 28 | .setInitialBranch('master') // for compatibility with existing tests 29 | .call() 30 | 31 | // Don't want the user's git config to conflict with test expectations 32 | git.repo.FS.userHome = null 33 | 34 | git.repo.config.with { 35 | setString('user', null, 'name', person.name) 36 | setString('user', null, 'email', person.email) 37 | save() 38 | } 39 | def grgit = Grgit.open(dir: repoDir) 40 | grgits.add(grgit) 41 | return grgit 42 | } 43 | 44 | protected Grgit clone(String name, Grgit remote) { 45 | File repoDir = new File(tempDir, name) 46 | def grgit = Grgit.clone { 47 | dir = repoDir 48 | uri = remote.repository.rootDir.toURI() 49 | } 50 | grgits.add(grgit) 51 | return grgit 52 | } 53 | 54 | protected File repoFile(Grgit grgit, String path, boolean makeDirs = true) { 55 | return GitTestUtil.repoFile(grgit, path, makeDirs) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/fixtures/SimpleGitOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.fixtures 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.Person 5 | 6 | import org.eclipse.jgit.api.Git 7 | 8 | import spock.lang.TempDir 9 | 10 | import spock.lang.Specification 11 | 12 | class SimpleGitOpSpec extends Specification { 13 | @TempDir 14 | File tempDir 15 | File repoDir 16 | 17 | Grgit grgit 18 | Person person = new Person('Bruce Wayne', 'bruce.wayne@wayneindustries.com') 19 | 20 | def setup() { 21 | repoDir = new File(tempDir, 'repo') 22 | Git git = Git.init() 23 | .setDirectory(repoDir) 24 | .setInitialBranch('master') // for compatibility with existing tests 25 | .call() 26 | 27 | // Don't want the user's git config to conflict with test expectations 28 | git.repo.FS.userHome = null 29 | 30 | git.repo.config.with { 31 | setString('user', null, 'name', person.name) 32 | setString('user', null, 'email', person.email) 33 | save() 34 | } 35 | grgit = Grgit.open(dir: repoDir) 36 | } 37 | 38 | def cleanup() { 39 | grgit.close() 40 | } 41 | 42 | protected File repoFile(String path, boolean makeDirs = true) { 43 | return GitTestUtil.repoFile(grgit, path, makeDirs) 44 | } 45 | 46 | protected File repoDir(String path) { 47 | return GitTestUtil.repoDir(grgit, path) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/AddOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Status 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | 6 | class AddOpSpec extends SimpleGitOpSpec { 7 | def 'adding specific file only adds that file'() { 8 | given: 9 | repoFile('1.txt') << '1' 10 | repoFile('2.txt') << '2' 11 | repoFile('test/3.txt') << '3' 12 | when: 13 | grgit.add(patterns:['1.txt']) 14 | then: 15 | grgit.status() == new Status( 16 | staged: [added: ['1.txt']], 17 | unstaged: [added: ['2.txt', 'test/3.txt']] 18 | ) 19 | } 20 | 21 | def 'adding specific directory adds all files within it'() { 22 | given: 23 | repoFile('1.txt') << '1' 24 | repoFile('something/2.txt') << '2' 25 | repoFile('test/3.txt') << '3' 26 | repoFile('test/4.txt') << '4' 27 | repoFile('test/other/5.txt') << '5' 28 | when: 29 | grgit.add(patterns:['test']) 30 | then: 31 | grgit.status() == new Status( 32 | staged: [added: ['test/3.txt', 'test/4.txt', 'test/other/5.txt']], 33 | unstaged: [added: ['1.txt', 'something/2.txt']] 34 | ) 35 | } 36 | 37 | def 'adding file pattern does not work due to lack of JGit support'() { 38 | given: 39 | repoFile('1.bat') << '1' 40 | repoFile('something/2.txt') << '2' 41 | repoFile('test/3.bat') << '3' 42 | repoFile('test/4.txt') << '4' 43 | repoFile('test/other/5.txt') << '5' 44 | when: 45 | grgit.add(patterns:['**/*.txt']) 46 | then: 47 | grgit.status() == new Status( 48 | unstaged: [added: ['1.bat', 'test/3.bat', 'something/2.txt', 'test/4.txt', 'test/other/5.txt']] 49 | ) 50 | /* 51 | * TODO: get it to work like this 52 | * status.added == ['something/2.txt', 'test/4.txt', 'test/other/5.txt'] as Set 53 | * status.untracked == ['1.bat', 'test/3.bat'] as Set 54 | */ 55 | } 56 | 57 | def 'adding with update true only adds/removes files already in the index'() { 58 | given: 59 | repoFile('1.bat') << '1' 60 | repoFile('something/2.txt') << '2' 61 | repoFile('test/3.bat') << '3' 62 | grgit.add(patterns:['.']) 63 | grgit.repository.jgit.commit().setMessage('Test').call() 64 | repoFile('1.bat') << '1' 65 | repoFile('something/2.txt') << '2' 66 | assert repoFile('test/3.bat').delete() 67 | repoFile('test/4.txt') << '4' 68 | repoFile('test/other/5.txt') << '5' 69 | when: 70 | grgit.add(patterns:['.'], update:true) 71 | then: 72 | grgit.status() == new Status( 73 | staged: [modified: ['1.bat', 'something/2.txt'], removed: ['test/3.bat']], 74 | unstaged: [added: ['test/4.txt', 'test/other/5.txt']] 75 | ) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/ApplyOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 4 | 5 | class ApplyOpSpec extends SimpleGitOpSpec { 6 | def 'apply with no patch fails'() { 7 | when: 8 | grgit.apply() 9 | then: 10 | thrown(IllegalStateException) 11 | } 12 | 13 | def 'apply with patch succeeds'() { 14 | given: 15 | repoFile('1.txt') << 'something' 16 | repoFile('2.txt') << 'something else\n' 17 | grgit.add(patterns:['.']) 18 | grgit.commit(message: 'Test') 19 | def patch = new File(tempDir, 'temp.patch') 20 | this.class.getResourceAsStream('/org/ajoberstar/grgit/operation/sample.patch').withStream { stream -> 21 | patch << stream 22 | } 23 | when: 24 | grgit.apply(patch: patch) 25 | then: 26 | repoFile('1.txt').text.normalize() == 'something' 27 | repoFile('2.txt').text.normalize() == 'something else\nis being added\n' 28 | repoFile('3.txt').text.normalize() == 'some new stuff\n' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/BranchChangeOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.fixtures.GitTestUtil 5 | import org.ajoberstar.grgit.fixtures.MultiGitOpSpec 6 | import org.eclipse.jgit.api.errors.GitAPIException 7 | 8 | import spock.lang.Unroll 9 | 10 | class BranchChangeOpSpec extends MultiGitOpSpec { 11 | Grgit localGrgit 12 | Grgit remoteGrgit 13 | 14 | List commits = [] 15 | 16 | def setup() { 17 | remoteGrgit = init('remote') 18 | 19 | repoFile(remoteGrgit, '1.txt') << '1' 20 | commits << remoteGrgit.commit(message: 'do', all: true) 21 | 22 | repoFile(remoteGrgit, '1.txt') << '2' 23 | commits << remoteGrgit.commit(message: 'do', all: true) 24 | 25 | remoteGrgit.checkout(branch: 'my-branch', createBranch: true) 26 | 27 | repoFile(remoteGrgit, '1.txt') << '3' 28 | commits << remoteGrgit.commit(message: 'do', all: true) 29 | 30 | localGrgit = clone('local', remoteGrgit) 31 | localGrgit.branch.add(name: 'local-branch') 32 | 33 | localGrgit.branch.add(name: 'test-branch', startPoint: commits[0].id) 34 | } 35 | 36 | def 'branch change with non-existent branch fails'() { 37 | when: 38 | localGrgit.branch.change(name: 'fake-branch', startPoint: 'test-branch') 39 | then: 40 | thrown(IllegalStateException) 41 | } 42 | 43 | def 'branch change with no start point fails'() { 44 | when: 45 | localGrgit.branch.change(name: 'local-branch') 46 | then: 47 | thrown(IllegalArgumentException) 48 | } 49 | 50 | @Unroll('branch change with #mode mode starting at #startPoint tracks #trackingBranch') 51 | def 'branch change with mode and start point behaves correctly'() { 52 | expect: 53 | localGrgit.branch.change(name: 'local-branch', startPoint: startPoint, mode: mode) == GitTestUtil.branch('refs/heads/local-branch', trackingBranch) 54 | localGrgit.resolve.toCommit('local-branch') == localGrgit.resolve.toCommit(startPoint) 55 | where: 56 | mode | startPoint | trackingBranch 57 | null | 'origin/my-branch' | 'refs/remotes/origin/my-branch' 58 | BranchChangeOp.Mode.TRACK | 'origin/my-branch' | 'refs/remotes/origin/my-branch' 59 | BranchChangeOp.Mode.NO_TRACK | 'origin/my-branch' | null 60 | null | 'test-branch' | null 61 | BranchChangeOp.Mode.TRACK | 'test-branch' | 'refs/heads/test-branch' 62 | BranchChangeOp.Mode.NO_TRACK | 'test-branch' | null 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/BranchListOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Commit 4 | import org.ajoberstar.grgit.Grgit 5 | import org.ajoberstar.grgit.fixtures.GitTestUtil 6 | import org.ajoberstar.grgit.fixtures.MultiGitOpSpec 7 | import spock.lang.Unroll 8 | 9 | class BranchListOpSpec extends MultiGitOpSpec { 10 | Grgit localGrgit 11 | Grgit remoteGrgit 12 | 13 | def setup() { 14 | remoteGrgit = init('remote') 15 | 16 | repoFile(remoteGrgit, '1.txt') << '1' 17 | remoteGrgit.commit(message: 'do', all: true) 18 | 19 | remoteGrgit.branch.add(name: 'my-branch') 20 | 21 | repoFile(remoteGrgit, '2.txt') << '2' 22 | remoteGrgit.commit(message: 'another', all: true) 23 | remoteGrgit.tag.add(name: 'test-tag'); 24 | 25 | localGrgit = clone('local', remoteGrgit) 26 | } 27 | 28 | @Unroll('list branch with #arguments lists #expected') 29 | def 'list branch without arguments only lists local'() { 30 | given: 31 | def expectedBranches = expected.collect { GitTestUtil.branch(*it) } 32 | def head = localGrgit.head() 33 | expect: 34 | localGrgit.branch.list(arguments) == expectedBranches 35 | where: 36 | arguments | expected 37 | [:] | [['refs/heads/master', 'refs/remotes/origin/master']] 38 | [mode: BranchListOp.Mode.LOCAL] | [['refs/heads/master', 'refs/remotes/origin/master']] 39 | [mode: BranchListOp.Mode.REMOTE] | [['refs/remotes/origin/master'], ['refs/remotes/origin/my-branch']] 40 | [mode: BranchListOp.Mode.ALL] | [['refs/heads/master', 'refs/remotes/origin/master'], ['refs/remotes/origin/master'], ['refs/remotes/origin/my-branch']] 41 | [mode: BranchListOp.Mode.REMOTE, contains: 'test-tag'] | [['refs/remotes/origin/master']] 42 | } 43 | 44 | def 'list branch receives Commit object as contains flag'() { 45 | given: 46 | def expectedBranches = [GitTestUtil.branch('refs/remotes/origin/master')] 47 | def head = localGrgit.head() 48 | def arguments = [mode: BranchListOp.Mode.REMOTE, contains: head] 49 | expect: 50 | localGrgit.branch.list(arguments) == expectedBranches 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/BranchRemoveOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Branch 4 | import org.ajoberstar.grgit.fixtures.GitTestUtil 5 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 6 | import org.eclipse.jgit.api.errors.GitAPIException 7 | 8 | import spock.lang.Unroll 9 | 10 | class BranchRemoveOpSpec extends SimpleGitOpSpec { 11 | def setup() { 12 | repoFile('1.txt') << '1' 13 | grgit.commit(message: 'do', all: true) 14 | 15 | grgit.branch.add(name: 'branch1') 16 | 17 | repoFile('1.txt') << '2' 18 | grgit.commit(message: 'do', all: true) 19 | 20 | grgit.branch.add(name: 'branch2') 21 | 22 | grgit.checkout(branch: 'branch3', createBranch: true) 23 | repoFile('1.txt') << '3' 24 | grgit.commit(message: 'do', all: true) 25 | 26 | grgit.checkout(branch: 'master') 27 | } 28 | 29 | def 'branch remove with empty list does nothing'() { 30 | expect: 31 | grgit.branch.remove() == [] 32 | grgit.branch.list() == branches('branch1', 'branch2', 'branch3', 'master') 33 | } 34 | 35 | def 'branch remove with one branch removes branch'() { 36 | expect: 37 | grgit.branch.remove(names: ['branch2']) == ['refs/heads/branch2'] 38 | grgit.branch.list() == branches('branch1', 'branch3', 'master') 39 | } 40 | 41 | def 'branch remove with multiple branches remvoes branches'() { 42 | expect: 43 | grgit.branch.remove(names: ['branch2', 'branch1']) == ['refs/heads/branch2', 'refs/heads/branch1'] 44 | grgit.branch.list() == branches('branch3', 'master') 45 | } 46 | 47 | def 'branch remove with invalid branches skips invalid and removes others'() { 48 | expect: 49 | grgit.branch.remove(names: ['branch2', 'blah4']) == ['refs/heads/branch2'] 50 | grgit.branch.list() == branches('branch1', 'branch3', 'master') 51 | } 52 | 53 | def 'branch remove with unmerged branch and force false fails'() { 54 | when: 55 | grgit.branch.remove(names: ['branch3']) 56 | then: 57 | thrown(GitAPIException) 58 | } 59 | 60 | def 'branch remove with unmerged branch and force true works'() { 61 | expect: 62 | grgit.branch.remove(names: ['branch3'], force: true) == ['refs/heads/branch3'] 63 | grgit.branch.list() == branches('branch1', 'branch2', 'master') 64 | } 65 | 66 | @Unroll('branch remove with current branch and force #force fails') 67 | def 'branch remove with current branch fails, even with force'() { 68 | when: 69 | grgit.branch.remove(names: ['master'], force: force) 70 | then: 71 | thrown(GitAPIException) 72 | where: 73 | force << [true, false] 74 | } 75 | 76 | private List branches(String... branches) { 77 | return branches.collect { GitTestUtil.branch("refs/heads/${it}") } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/BranchStatusOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.BranchStatus 4 | import org.ajoberstar.grgit.Grgit 5 | import org.ajoberstar.grgit.fixtures.GitTestUtil 6 | import org.ajoberstar.grgit.fixtures.MultiGitOpSpec 7 | import org.eclipse.jgit.api.errors.GitAPIException 8 | 9 | import spock.lang.Unroll 10 | 11 | class BranchStatusOpSpec extends MultiGitOpSpec { 12 | Grgit localGrgit 13 | Grgit remoteGrgit 14 | 15 | def setup() { 16 | remoteGrgit = init('remote') 17 | 18 | repoFile(remoteGrgit, '1.txt') << '1' 19 | remoteGrgit.commit(message: 'do', all: true) 20 | 21 | remoteGrgit.checkout(branch: 'up-to-date', createBranch: true) 22 | 23 | repoFile(remoteGrgit, '1.txt') << '2' 24 | remoteGrgit.commit(message: 'do', all: true) 25 | 26 | remoteGrgit.checkout(branch: 'master') 27 | remoteGrgit.checkout(branch: 'out-of-date', createBranch: true) 28 | remoteGrgit.checkout(branch: 'master') 29 | 30 | localGrgit = clone('local', remoteGrgit) 31 | 32 | localGrgit.branch.add(name: 'up-to-date', startPoint: 'origin/up-to-date') 33 | localGrgit.branch.add(name: 'out-of-date', startPoint: 'origin/out-of-date') 34 | localGrgit.checkout(branch: 'out-of-date') 35 | 36 | remoteGrgit.checkout(branch: 'out-of-date') 37 | repoFile(remoteGrgit, '1.txt') << '3' 38 | remoteGrgit.commit(message: 'do', all: true) 39 | 40 | repoFile(localGrgit, '1.txt') << '4' 41 | localGrgit.commit(message: 'do', all: true) 42 | repoFile(localGrgit, '1.txt') << '5' 43 | localGrgit.commit(message: 'do', all: true) 44 | 45 | localGrgit.branch.add(name: 'no-track') 46 | 47 | localGrgit.fetch() 48 | } 49 | 50 | def 'branch status on branch that is not tracking fails'() { 51 | when: 52 | localGrgit.branch.status(name: 'no-track') 53 | then: 54 | thrown(IllegalStateException) 55 | } 56 | 57 | @Unroll('branch status on #branch gives correct counts') 58 | def 'branch status on branch that is tracking gives correct counts'() { 59 | expect: 60 | localGrgit.branch.status(name: branch) == status 61 | where: 62 | branch | status 63 | 'up-to-date' | new BranchStatus(branch: GitTestUtil.branch('refs/heads/up-to-date', 'refs/remotes/origin/up-to-date'), aheadCount: 0, behindCount: 0) 64 | 'out-of-date' | new BranchStatus(branch: GitTestUtil.branch('refs/heads/out-of-date', 'refs/remotes/origin/out-of-date'), aheadCount: 2, behindCount: 1) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/CleanOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 4 | 5 | class CleanOpSpec extends SimpleGitOpSpec { 6 | def setup() { 7 | repoFile('.gitignore') << 'build/\n.project' 8 | repoFile('1.txt') << '.' 9 | repoFile('2.txt') << '.' 10 | repoFile('3.txt') << '.' 11 | repoFile('dir1/4.txt') << '.' 12 | repoFile('dir1/5.txt') << '.' 13 | repoFile('dir1/6.txt') << '.' 14 | repoFile('dir2/7.txt') << '.' 15 | repoFile('dir2/8.txt') << '.' 16 | repoDir('dir1/dir3') 17 | repoDir('dir2/dir4') 18 | repoDir('dir5') 19 | repoFile('build/8.txt') << '.' 20 | repoFile('.project') << '.' 21 | 22 | grgit.add(patterns: ['.gitignore', '1.txt', '2.txt', 'dir1', 'dir2/8.txt']) 23 | grgit.commit(message: 'do') 24 | } 25 | 26 | def 'clean with defaults deletes untracked files only'() { 27 | given: 28 | def expected = ['3.txt', 'dir2/7.txt'] as Set 29 | expect: 30 | grgit.clean() == expected 31 | expected.every { !repoFile(it).exists() } 32 | } 33 | 34 | def 'clean with paths only deletes from paths'() { 35 | given: 36 | def expected = ['dir2/7.txt'] as Set 37 | expect: 38 | grgit.clean(paths: ['dir2/7.txt']) == expected 39 | expected.every { !repoFile(it).exists() } 40 | } 41 | 42 | def 'clean with directories true also deletes untracked directories'() { 43 | given: 44 | def expected = ['3.txt', 'dir2/7.txt', 'dir5/', 'dir2/dir4/', 'dir1/dir3/'] as Set 45 | expect: 46 | grgit.clean(directories: true) == expected 47 | expected.every { !repoFile(it).exists() } 48 | } 49 | 50 | def 'clean with ignore false also deletes files ignored by .gitignore'() { 51 | given: 52 | def expected = ['3.txt', 'dir2/7.txt', '.project'] as Set 53 | expect: 54 | grgit.clean(ignore: false) == expected 55 | expected.every { !repoFile(it).exists() } 56 | } 57 | 58 | def 'clean with dry run true returns expected but does not delete them'() { 59 | given: 60 | def expected = ['3.txt', 'dir2/7.txt'] as Set 61 | expect: 62 | grgit.clean(dryRun: true) == expected 63 | expected.every { repoFile(it).exists() } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/DescribeOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 4 | 5 | class DescribeOpSpec extends SimpleGitOpSpec { 6 | def setup() { 7 | grgit.commit(message:'initial commit') 8 | 9 | grgit.commit(message:'second commit') 10 | grgit.tag.add(name:'second') 11 | 12 | grgit.commit(message:'another commit') 13 | grgit.tag.add(name:'another') 14 | 15 | grgit.commit(message:'other commit') 16 | grgit.tag.add(name:'other', annotate: false) 17 | } 18 | 19 | def 'without tag'() { 20 | given: 21 | grgit.reset(commit: 'HEAD~3', mode: 'hard') 22 | expect: 23 | grgit.describe() == null 24 | grgit.describe(always: true) == grgit.head().abbreviatedId 25 | } 26 | 27 | def 'with tag'() { 28 | given: 29 | grgit.reset(commit: 'HEAD~1', mode: 'hard') 30 | expect: 31 | grgit.describe() == 'another' 32 | } 33 | 34 | def 'with additional commit'(){ 35 | given: 36 | repoFile('1.txt') << '1' 37 | grgit.add(patterns:['1.txt']) 38 | grgit.commit(message: 'another commit') 39 | expect: 40 | grgit.describe().startsWith('another-2-') 41 | } 42 | 43 | def 'from different commit'(){ 44 | given: 45 | repoFile('1.txt') << '1' 46 | grgit.add(patterns:['1.txt']) 47 | grgit.commit(message: 'another commit') 48 | expect: 49 | grgit.describe(commit: 'HEAD~3') == 'second' 50 | } 51 | 52 | def 'with long description'() { 53 | expect: 54 | grgit.describe(longDescr: true).startsWith('another-1-') 55 | } 56 | 57 | def 'with un-annotated tags'() { 58 | expect: 59 | grgit.describe(tags: true) == 'other' 60 | } 61 | 62 | def 'with match'() { 63 | expect: 64 | grgit.describe(match: ['second*']).startsWith('second-2-') 65 | } 66 | 67 | def 'with abbrev'() { 68 | expect: 69 | grgit.describe(abbrev: abbrev) ==~ expectedPattern 70 | 71 | where: 72 | abbrev | expectedPattern 73 | 0 | /^another$/ 74 | 30 | /^another-1-g.{30}$/ 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/DiffOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Commit 4 | import org.ajoberstar.grgit.CommitDiff 5 | import org.ajoberstar.grgit.DiffEntry 6 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 7 | 8 | class DiffOpSpec extends SimpleGitOpSpec { 9 | 10 | def 'can show diffs in commit that added new file'() { 11 | File fooFile = repoFile("dir0/foo1.txt") 12 | fooFile << "foo!" 13 | grgit.add(patterns: ['.']) 14 | Commit commit = grgit.commit(message: "Initial commit") 15 | 16 | File fooFile2 = repoFile("dir0/foo2.txt") 17 | fooFile2 << "foo!" 18 | grgit.add(patterns: ['.']) 19 | Commit commit2 = grgit.commit(message: "Initial commit") 20 | 21 | expect: 22 | grgit.diff(oldCommit: commit)[0] == new DiffEntry( 23 | changeType: DiffEntry.ChangeType.ADD, 24 | oldPath: '/dev/null', 25 | newPath: 'dir0/foo2.txt' 26 | ) 27 | } 28 | 29 | def 'can show diffs in commit that modified existing file'() { 30 | File fooFile = repoFile("dir1/foo.txt") 31 | fooFile << "foo!" 32 | grgit.add(patterns: ['.']) 33 | Commit commit = grgit.commit(message: "Initial commit") 34 | // modify the file and commit again 35 | fooFile << "foo!!!" 36 | grgit.add(patterns: ['.']) 37 | Commit commit2 = grgit.commit(message: "Second commit") 38 | 39 | expect: 40 | grgit.diff(oldCommit: commit)[0] == new DiffEntry( 41 | changeType: DiffEntry.ChangeType.MODIFY, 42 | oldPath: 'dir1/foo.txt', 43 | newPath: 'dir1/foo.txt' 44 | ) 45 | } 46 | 47 | def 'can show diffs between two commits that modified existing file usig pathFilter'() { 48 | File fooFile = repoFile("dir2/foo.txt") 49 | fooFile << "foo!" 50 | grgit.add(patterns: ['.']) 51 | Commit commit = grgit.commit(message: "Initial commit") 52 | // modify the file and commit again 53 | fooFile << "foo!!!" 54 | grgit.add(patterns: ['.']) 55 | Commit commit2 = grgit.commit(message: "Second commit") 56 | 57 | expect: 58 | grgit.diff(oldCommit: commit, newCommit: commit2, pathFilter: 'dir2/foo.txt')[0] == new DiffEntry( 59 | changeType: DiffEntry.ChangeType.MODIFY, 60 | oldPath: 'dir2/foo.txt', 61 | newPath: 'dir2/foo.txt' 62 | ) 63 | } 64 | 65 | 66 | def 'can show diffs in commit that deleted existing file'() { 67 | File fooFile = repoFile("bar.txt") 68 | fooFile << "bar!" 69 | grgit.add(patterns: ['.']) 70 | Commit commit = grgit.commit(message: "Initial commit") 71 | 72 | // Delete existing file 73 | grgit.remove(patterns: ['bar.txt']) 74 | Commit removeCommit = grgit.commit(message: "Deleted file") 75 | 76 | expect: 77 | grgit.diff(oldCommit: commit)[0] == new DiffEntry( 78 | changeType: DiffEntry.ChangeType.DELETE, 79 | oldPath: 'bar.txt', 80 | newPath: '/dev/null' 81 | ) 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/GenericOpTest.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | import java.util.HashSet; 9 | 10 | import org.ajoberstar.grgit.Grgit; 11 | import org.junit.jupiter.api.DisplayName; 12 | import org.junit.jupiter.api.Test; 13 | import org.junit.jupiter.api.io.TempDir; 14 | 15 | public class GenericOpTest { 16 | @TempDir 17 | public File tempDir; 18 | 19 | @Test 20 | @DisplayName("consumer operation works") 21 | public void consumerOperationWorks() throws IOException { 22 | Grgit grgit = Grgit.init(op -> { 23 | op.setDir(tempDir); 24 | }); 25 | grgit.add(op -> { 26 | op.setPatterns(new HashSet<>(Arrays.asList("."))); 27 | }); 28 | grgit.commit(op -> { 29 | op.setMessage("First commit"); 30 | }); 31 | assertEquals(1, grgit.log().size()); 32 | grgit.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/HeadSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.fixtures.GitTestUtil 5 | 6 | import spock.lang.TempDir 7 | 8 | import spock.lang.Specification 9 | 10 | class HeadSpec extends Specification { 11 | @TempDir 12 | File repoDir 13 | 14 | def 'head on a newly initialized repo returns null'() { 15 | given: 16 | def grgit = Grgit.init(dir: repoDir) 17 | expect: 18 | grgit.head() == null 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/InitOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.fixtures.GitTestUtil 5 | 6 | import spock.lang.TempDir 7 | 8 | import spock.lang.Specification 9 | 10 | class InitOpSpec extends Specification { 11 | @TempDir 12 | File repoDir 13 | 14 | def 'init with bare true does not have a working tree'() { 15 | when: 16 | def grgit = Grgit.init(dir: repoDir, bare: true) 17 | then: 18 | !GitTestUtil.repoFile(grgit, '.', false).listFiles().collect { it.name }.contains('.git') 19 | } 20 | 21 | def 'init with bare false has a working tree'() { 22 | when: 23 | def grgit = Grgit.init(dir: repoDir, bare: false) 24 | then: 25 | GitTestUtil.repoFile(grgit, '.', false).listFiles().collect { it.name } == ['.git'] 26 | } 27 | 28 | def 'init repo can be deleted after being closed'() { 29 | given: 30 | def grgit = Grgit.init(dir: repoDir, bare: false) 31 | when: 32 | grgit.close() 33 | then: 34 | repoDir.deleteDir() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/LogOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | import org.ajoberstar.grgit.util.JGitUtil 6 | 7 | import org.eclipse.jgit.merge.MergeStrategy 8 | 9 | class LogOpSpec extends SimpleGitOpSpec { 10 | List commits = [] 11 | 12 | def intToCommit = { commits[it] } 13 | 14 | def setup() { 15 | // TODO: Convert to Grgit when merge available 16 | File testFile1 = repoFile('1.txt') 17 | File testFile2 = repoFile('2.txt') 18 | 19 | testFile1 << '1' 20 | testFile2 << '2.1' 21 | grgit.add(patterns: ['.']) 22 | commits << grgit.commit(message: 'first commit\ntesting') 23 | 24 | testFile1 << '2' 25 | grgit.add(patterns: ['.']) 26 | commits << grgit.commit(message: 'second commit') 27 | grgit.tag.add(name: 'v1.0.0', message: 'annotated tag') 28 | 29 | grgit.checkout(branch: intToCommit(0).id) 30 | testFile1 << '3' 31 | grgit.add(patterns: ['.']) 32 | commits << grgit.commit(message: 'third commit') 33 | 34 | grgit.checkout(branch: 'master') 35 | def jgitId = JGitUtil.resolveObject(grgit.repository, commits[2].id) 36 | def mergeCommit = grgit.repository.jgit.merge().include(jgitId).setStrategy(MergeStrategy.OURS).call().newHead 37 | commits << JGitUtil.convertCommit(grgit.repository, mergeCommit) 38 | 39 | testFile1 << '4' 40 | grgit.add(patterns: ['.']) 41 | commits << grgit.commit(message: 'fifth commit') 42 | 43 | testFile2 << '2.2' 44 | grgit.add(patterns: ['.']) 45 | commits << grgit.commit(message: 'sixth commit') 46 | } 47 | 48 | def 'log with no arguments returns all commits'() { 49 | expect: 50 | grgit.log() in [[5, 4, 3, 2, 1, 0], [5, 4, 3, 1, 2, 0]]*.collect(intToCommit) 51 | } 52 | 53 | def 'log with max commits returns that number of commits'() { 54 | expect: 55 | grgit.log(maxCommits:2) == [5, 4].collect(intToCommit) 56 | } 57 | 58 | def 'log with skip commits does not return the first x commits'() { 59 | expect: 60 | grgit.log(skipCommits:2) in [[3, 2, 1, 0], [3, 1, 2, 0]]*.collect(intToCommit) 61 | } 62 | 63 | def 'log with range returns only the commits in that range'() { 64 | expect: 65 | grgit.log { 66 | range intToCommit(2).id, intToCommit(4).id 67 | } == [4, 3, 1].collect(intToCommit) 68 | } 69 | 70 | def 'log with non-existing commit fails'() { 71 | when: 72 | grgit.log(includes: ['garbage', intToCommit(1)]) 73 | then: 74 | thrown(IllegalArgumentException) 75 | } 76 | 77 | def 'log with path includes only commits with changes for that path'() { 78 | expect: 79 | grgit.log(paths:['2.txt']).collect { it.id } == [5, 0].collect(intToCommit).collect { it.id } 80 | } 81 | 82 | def 'log with annotated tag short name works'() { 83 | expect: 84 | grgit.log(includes: ['v1.0.0']) == [1, 0].collect(intToCommit) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/LsRemoteOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.Ref 5 | import org.ajoberstar.grgit.fixtures.MultiGitOpSpec 6 | import org.eclipse.jgit.api.errors.GitAPIException 7 | 8 | import spock.lang.Unroll 9 | 10 | class LsRemoteOpSpec extends MultiGitOpSpec { 11 | Grgit localGrgit 12 | Grgit remoteGrgit 13 | 14 | List branches = [] 15 | List tags = [] 16 | 17 | def setup() { 18 | remoteGrgit = init('remote') 19 | 20 | branches << remoteGrgit.branch.current 21 | 22 | repoFile(remoteGrgit, '1.txt') << '1' 23 | remoteGrgit.commit(message: 'do', all: true) 24 | 25 | branches << remoteGrgit.branch.add(name: 'my-branch') 26 | 27 | localGrgit = clone('local', remoteGrgit) 28 | 29 | repoFile(remoteGrgit, '1.txt') << '2' 30 | remoteGrgit.commit(message: 'do', all: true) 31 | 32 | tags << remoteGrgit.tag.add(name: 'reachable-tag') 33 | branches << remoteGrgit.branch.add(name: 'sub/mine1') 34 | 35 | remoteGrgit.checkout { 36 | branch = 'unreachable-branch' 37 | createBranch = true 38 | } 39 | branches << remoteGrgit.branch.list().find { it.name == 'unreachable-branch' } 40 | 41 | repoFile(remoteGrgit, '1.txt') << '2.5' 42 | remoteGrgit.commit(message: 'do-unreachable', all: true) 43 | 44 | tags << remoteGrgit.tag.add(name: 'unreachable-tag') 45 | 46 | remoteGrgit.checkout(branch: 'master') 47 | 48 | repoFile(remoteGrgit, '1.txt') << '3' 49 | remoteGrgit.commit(message: 'do', all: true) 50 | 51 | branches << remoteGrgit.branch.add(name: 'sub/mine2') 52 | 53 | println remoteGrgit.branch.list() 54 | println remoteGrgit.tag.list() 55 | } 56 | 57 | def 'lsremote from non-existent remote fails'() { 58 | when: 59 | localGrgit.lsremote(remote: 'fake') 60 | then: 61 | thrown(GitAPIException) 62 | } 63 | 64 | def 'lsremote returns all refs'() { 65 | expect: 66 | localGrgit.lsremote() == format([new Ref('HEAD'), branches, tags].flatten()) 67 | } 68 | 69 | def 'lsremote returns branches and tags'() { 70 | expect: 71 | localGrgit.lsremote(heads: true, tags: true) == format([branches, tags].flatten()) 72 | } 73 | 74 | def 'lsremote returns only branches'() { 75 | expect: 76 | localGrgit.lsremote(heads: true) == format(branches) 77 | } 78 | 79 | def 'lsremote returns only tags'() { 80 | expect: 81 | localGrgit.lsremote(tags: true) == format(tags) 82 | } 83 | 84 | private Map format(things) { 85 | return things.collectEntries { refish -> 86 | Ref ref = new Ref(refish.fullName) 87 | [(ref): remoteGrgit.resolve.toObjectId(refish)] 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/RemoteAddOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Remote 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | 6 | class RemoteAddOpSpec extends SimpleGitOpSpec { 7 | 8 | def 'remote with given name and push/fetch urls is added'() { 9 | given: 10 | Remote remote = new Remote( 11 | name: 'newRemote', 12 | url: 'http://fetch.url/', 13 | fetchRefSpecs: ['+refs/heads/*:refs/remotes/newRemote/*']) 14 | expect: 15 | remote == grgit.remote.add(name: 'newRemote', url: 'http://fetch.url/') 16 | [remote] == grgit.remote.list() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/RemoteListOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.ajoberstar.grgit.Remote 5 | import org.ajoberstar.grgit.fixtures.MultiGitOpSpec 6 | 7 | class RemoteListOpSpec extends MultiGitOpSpec { 8 | def 'will list all remotes'() { 9 | given: 10 | Grgit remoteGrgit = init('remote') 11 | 12 | repoFile(remoteGrgit, '1.txt') << '1' 13 | remoteGrgit.commit(message: 'do', all: true) 14 | 15 | Grgit localGrgit = clone('local', remoteGrgit) 16 | 17 | expect: 18 | localGrgit.remote.list() == [ 19 | new Remote( 20 | name: 'origin', 21 | url: remoteGrgit.repository.rootDir.canonicalFile.toPath().toUri(), 22 | fetchRefSpecs: ['+refs/heads/*:refs/remotes/origin/*']) 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/RemoveRemoveOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 4 | 5 | class RemoveRemoveOpSpec extends SimpleGitOpSpec { 6 | def 'remote with given name is removed'() { 7 | given: 8 | grgit.remote.add(name: 'newRemote', url: 'http://fetch.url/') 9 | when: 10 | grgit.remote.remove(name: 'newRemote') 11 | then: 12 | [] == grgit.remote.list() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/ResetOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Status 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | 6 | class ResetOpSpec extends SimpleGitOpSpec { 7 | List commits = [] 8 | 9 | def setup() { 10 | repoFile('1.bat') << '1' 11 | repoFile('something/2.txt') << '2' 12 | repoFile('test/3.bat') << '3' 13 | repoFile('test/4.txt') << '4' 14 | repoFile('test/other/5.txt') << '5' 15 | grgit.add(patterns:['.']) 16 | commits << grgit.commit(message: 'Test') 17 | repoFile('1.bat') << '2' 18 | repoFile('test/3.bat') << '4' 19 | grgit.add(patterns:['.']) 20 | commits << grgit.commit(message: 'Test') 21 | repoFile('1.bat') << '3' 22 | repoFile('something/2.txt') << '2' 23 | grgit.add(patterns:['.']) 24 | repoFile('test/other/5.txt') << '6' 25 | repoFile('test/4.txt') << '5' 26 | } 27 | 28 | def 'reset soft changes HEAD only'() { 29 | when: 30 | grgit.reset(mode:'soft', commit:commits[0].id) 31 | then: 32 | commits[0] == grgit.head() 33 | grgit.status() == new Status( 34 | staged: [modified: ['1.bat', 'test/3.bat', 'something/2.txt']], 35 | unstaged: [modified: ['test/4.txt', 'test/other/5.txt']] 36 | ) 37 | } 38 | 39 | def 'reset mixed changes HEAD and index'() { 40 | when: 41 | grgit.reset(mode:'mixed', commit:commits[0].id) 42 | then: 43 | commits[0] == grgit.head() 44 | grgit.status() == new Status( 45 | unstaged: [modified: ['1.bat', 'test/3.bat', 'test/4.txt', 'something/2.txt', 'test/other/5.txt']]) 46 | } 47 | 48 | def 'reset hard changes HEAD, index, and working tree'() { 49 | when: 50 | grgit.reset(mode:'hard', commit:commits[0].id) 51 | then: 52 | commits[0] == grgit.head() 53 | grgit.status().clean 54 | } 55 | 56 | def 'reset with paths changes index only'() { 57 | when: 58 | grgit.reset(paths:['something/2.txt']) 59 | then: 60 | commits[1] == grgit.head() 61 | grgit.status() == new Status( 62 | staged: [modified: ['1.bat']], 63 | unstaged: [modified: ['test/4.txt', 'something/2.txt', 'test/other/5.txt']] 64 | ) 65 | } 66 | 67 | def 'reset with paths and mode set not supported'() { 68 | when: 69 | grgit.reset(mode:'hard', paths:['.']) 70 | then: 71 | thrown(IllegalStateException) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/RevertOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 4 | 5 | class RevertOpSpec extends SimpleGitOpSpec { 6 | List commits = [] 7 | 8 | def setup() { 9 | 5.times { 10 | repoFile("${it}.txt") << "1" 11 | grgit.add(patterns:['.']) 12 | commits << grgit.commit(message:'Test', all: true) 13 | } 14 | } 15 | 16 | def 'revert with no commits does nothing'() { 17 | when: 18 | grgit.revert() 19 | then: 20 | grgit.log().size() == 5 21 | } 22 | 23 | def 'revert with commits removes associated changes'() { 24 | when: 25 | grgit.revert(commits:[1, 3].collect { commits[it].id }) 26 | then: 27 | grgit.log().size() == 7 28 | repoFile('.').listFiles().collect { it.name }.findAll { !it.startsWith('.') } as Set == [0, 2, 4].collect { "${it}.txt" } as Set 29 | } 30 | 31 | def 'revert with conflicts raises exception'() { 32 | given: 33 | repoFile("1.txt") << "Edited" 34 | grgit.add(patterns:['.']) 35 | commits << grgit.commit(message:'Modified', all: true) 36 | when: 37 | grgit.revert(commits:[1, 3].collect { commits[it].id }) 38 | then: 39 | thrown(IllegalStateException) 40 | grgit.log().size() == 6 41 | grgit.status().conflicts.containsAll('1.txt') 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/RmOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Status 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | 6 | class RmOpSpec extends SimpleGitOpSpec { 7 | def setup() { 8 | repoFile('1.bat') << '1' 9 | repoFile('something/2.txt') << '2' 10 | repoFile('test/3.bat') << '3' 11 | repoFile('test/4.txt') << '4' 12 | repoFile('test/other/5.txt') << '5' 13 | grgit.add(patterns:['.']) 14 | grgit.commit(message: 'Test') 15 | } 16 | 17 | def 'removing specific file only removes that file'() { 18 | given: 19 | def paths = ['1.bat'] as Set 20 | when: 21 | grgit.remove(patterns:['1.bat']) 22 | then: 23 | grgit.status() == new Status(staged: [removed: paths]) 24 | paths.every { !repoFile(it).exists() } 25 | } 26 | 27 | def 'removing specific directory removes all files within it'() { 28 | given: 29 | def paths = ['test/3.bat', 'test/4.txt', 'test/other/5.txt'] as Set 30 | when: 31 | grgit.remove(patterns:['test']) 32 | then: 33 | grgit.status() == new Status(staged: [removed: paths]) 34 | paths.every { !repoFile(it).exists() } 35 | } 36 | 37 | def 'removing file pattern does not work due to lack of JGit support'() { 38 | given: 39 | def paths = ['1.bat', 'something/2.txt', 'test/3.bat', 'test/4.txt', 'test/other/5.txt'] as Set 40 | when: 41 | grgit.remove(patterns:['**/*.txt']) 42 | then: 43 | grgit.status().clean 44 | /* 45 | * TODO: get it to work like this 46 | * status.removed == ['something/2.txt', 'test/4.txt', 'test/other/5.txt'] as Set 47 | */ 48 | paths.every { repoFile(it).exists() } 49 | } 50 | 51 | def 'removing with cached true only removes files from index'() { 52 | given: 53 | def paths = ['something/2.txt'] as Set 54 | when: 55 | grgit.remove(patterns:['something'], cached:true) 56 | then: 57 | grgit.status() == new Status(staged: [removed: paths], unstaged: [added: paths]) 58 | paths.every { repoFile(it).exists() } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/StatusOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Status 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | import org.eclipse.jgit.api.errors.GitAPIException 6 | 7 | class StatusOpSpec extends SimpleGitOpSpec { 8 | def setup() { 9 | 4.times { repoFile("${it}.txt") << "1" } 10 | grgit.add(patterns: ['.']) 11 | grgit.commit(message: 'Test') 12 | grgit.checkout(branch: 'conflict', createBranch: true) 13 | repoFile('1.txt') << '2' 14 | grgit.add(patterns: ['.']) 15 | grgit.commit(message: 'conflicting change') 16 | grgit.checkout(branch: 'master') 17 | repoFile('1.txt') << '3' 18 | grgit.add(patterns: ['.']) 19 | grgit.commit(message: 'other change') 20 | } 21 | 22 | def 'with no changes all methods return empty list'() { 23 | expect: 24 | grgit.status() == new Status() 25 | } 26 | 27 | def 'new unstaged file detected'() { 28 | given: 29 | repoFile('5.txt') << '5' 30 | repoFile('6.txt') << '6' 31 | expect: 32 | grgit.status() == new Status(unstaged: [added: ['5.txt', '6.txt']]) 33 | } 34 | 35 | def 'unstaged modified files detected'() { 36 | given: 37 | repoFile('2.txt') << '2' 38 | repoFile('3.txt') << '3' 39 | expect: 40 | grgit.status() == new Status(unstaged: [modified: ['2.txt', '3.txt']]) 41 | } 42 | 43 | def 'unstaged deleted files detected'() { 44 | given: 45 | assert repoFile('1.txt').delete() 46 | assert repoFile('2.txt').delete() 47 | expect: 48 | grgit.status() == new Status(unstaged: [removed: ['1.txt', '2.txt']]) 49 | } 50 | 51 | def 'staged new files detected'() { 52 | given: 53 | repoFile('5.txt') << '5' 54 | repoFile('6.txt') << '6' 55 | when: 56 | grgit.add(patterns: ['.']) 57 | then: 58 | grgit.status() == new Status(staged: [added: ['5.txt', '6.txt']]) 59 | } 60 | 61 | def 'staged modified files detected'() { 62 | given: 63 | repoFile('1.txt') << '5' 64 | repoFile('2.txt') << '6' 65 | when: 66 | grgit.add(patterns: ['.']) 67 | then: 68 | grgit.status() == new Status(staged: [modified: ['1.txt', '2.txt']]) 69 | } 70 | 71 | def 'staged removed files detected'() { 72 | given: 73 | assert repoFile('3.txt').delete() 74 | assert repoFile('0.txt').delete() 75 | when: 76 | grgit.add(patterns: ['.'], update: true) 77 | then: 78 | grgit.status() == new Status(staged: [removed: ['3.txt', '0.txt']]) 79 | } 80 | 81 | def 'conflict files detected'() { 82 | when: 83 | grgit.merge(head: 'conflict') 84 | then: 85 | grgit.status() == new Status(conflicts: ['1.txt']) 86 | thrown(IllegalStateException) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/TagAddOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import java.time.Instant 4 | import java.time.ZoneId 5 | import java.time.ZonedDateTime 6 | import java.time.temporal.ChronoField 7 | 8 | import org.ajoberstar.grgit.Tag 9 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 10 | import org.eclipse.jgit.api.errors.GitAPIException 11 | 12 | class TagAddOpSpec extends SimpleGitOpSpec { 13 | List commits = [] 14 | 15 | def setup() { 16 | repoFile('1.txt') << '1' 17 | commits << grgit.commit(message: 'do', all: true) 18 | 19 | repoFile('1.txt') << '2' 20 | commits << grgit.commit(message: 'do', all: true) 21 | 22 | repoFile('1.txt') << '3' 23 | commits << grgit.commit(message: 'do', all: true) 24 | } 25 | 26 | def 'tag add creates annotated tag pointing to current HEAD'() { 27 | given: 28 | Instant instant = Instant.now().with(ChronoField.NANO_OF_SECOND, 0) 29 | ZoneId zone = ZoneId.ofOffset('GMT', ZoneId.systemDefault().getRules().getOffset(instant)) 30 | ZonedDateTime tagTime = ZonedDateTime.ofInstant(instant, zone) 31 | when: 32 | grgit.tag.add(name: 'test-tag') 33 | then: 34 | grgit.tag.list() == [new Tag( 35 | commits[2], 36 | person, 37 | 'refs/tags/test-tag', 38 | '', 39 | '', 40 | tagTime 41 | )] 42 | grgit.resolve.toCommit('test-tag') == grgit.head() 43 | } 44 | 45 | def 'tag add with annotate false creates unannotated tag pointing to current HEAD'() { 46 | when: 47 | grgit.tag.add(name: 'test-tag', annotate: false) 48 | then: 49 | grgit.tag.list() == [new Tag( 50 | commits[2], 51 | null, 52 | 'refs/tags/test-tag', 53 | null, 54 | null, 55 | null 56 | )] 57 | grgit.resolve.toCommit('test-tag') == grgit.head() 58 | } 59 | 60 | def 'tag add with name and pointsTo creates tag pointing to pointsTo'() { 61 | given: 62 | Instant instant = Instant.now().with(ChronoField.NANO_OF_SECOND, 0) 63 | ZoneId zone = ZoneId.ofOffset('GMT', ZoneId.systemDefault().getRules().getOffset(instant)) 64 | ZonedDateTime tagTime = ZonedDateTime.ofInstant(instant, zone) 65 | when: 66 | grgit.tag.add(name: 'test-tag', pointsTo: commits[0].id) 67 | then: 68 | grgit.tag.list() == [new Tag( 69 | commits[0], 70 | person, 71 | 'refs/tags/test-tag', 72 | '', 73 | '', 74 | tagTime 75 | )] 76 | grgit.resolve.toCommit('test-tag') == commits[0] 77 | } 78 | 79 | def 'tag add without force fails to overwrite existing tag'() { 80 | given: 81 | grgit.tag.add(name: 'test-tag', pointsTo: commits[0].id) 82 | when: 83 | grgit.tag.add(name: 'test-tag') 84 | then: 85 | thrown(GitAPIException) 86 | } 87 | 88 | def 'tag add with force overwrites existing tag'() { 89 | given: 90 | grgit.tag.add(name: 'test-tag', pointsTo: commits[0].id) 91 | when: 92 | grgit.tag.add(name: 'test-tag', force: true) 93 | then: 94 | grgit.resolve.toCommit('test-tag') == grgit.head() 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/TagListOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.Tag 4 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 5 | 6 | class TagListOpSpec extends SimpleGitOpSpec { 7 | List commits = [] 8 | List tags = [] 9 | 10 | def setup() { 11 | repoFile('1.txt') << '1' 12 | commits << grgit.commit(message: 'do', all: true) 13 | tags << grgit.tag.add(name: 'tag1', message: 'My message') 14 | 15 | repoFile('1.txt') << '2' 16 | commits << grgit.commit(message: 'do', all: true) 17 | tags << grgit.tag.add(name: 'tag2', message: 'My other\nmessage') 18 | 19 | tags << grgit.tag.add(name: 'tag3', message: 'My next message.', pointsTo: 'tag1') 20 | } 21 | 22 | def 'tag list lists all tags'() { 23 | expect: 24 | grgit.tag.list() == tags 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /grgit-core/src/test/groovy/org/ajoberstar/grgit/operation/TagRemoveOpSpec.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.operation 2 | 3 | import org.ajoberstar.grgit.fixtures.SimpleGitOpSpec 4 | 5 | class TagRemoveOpSpec extends SimpleGitOpSpec { 6 | def setup() { 7 | repoFile('1.txt') << '1' 8 | grgit.commit(message: 'do', all: true) 9 | grgit.tag.add(name: 'tag1') 10 | 11 | repoFile('1.txt') << '2' 12 | grgit.commit(message: 'do', all: true) 13 | grgit.tag.add(name: 'tag2', annotate: false) 14 | } 15 | 16 | def 'tag remove with empty list does nothing'() { 17 | expect: 18 | grgit.tag.remove() == [] 19 | grgit.tag.list().collect { it.fullName } == ['refs/tags/tag1', 'refs/tags/tag2'] 20 | } 21 | 22 | def 'tag remove with one tag removes tag'() { 23 | expect: 24 | grgit.tag.remove(names: ['tag2']) == ['refs/tags/tag2'] 25 | grgit.tag.list().collect { it.fullName } == ['refs/tags/tag1'] 26 | } 27 | 28 | def 'tag remove with multiple tags removes tags'() { 29 | expect: 30 | grgit.tag.remove(names: ['tag2', 'tag1']) as Set == ['refs/tags/tag2', 'refs/tags/tag1'] as Set 31 | grgit.tag.list() == [] 32 | } 33 | 34 | def 'tag remove with invalid tags skips invalid and removes others'() { 35 | expect: 36 | grgit.tag.remove(names: ['tag2', 'blah4']) == ['refs/tags/tag2'] 37 | grgit.tag.list().collect { it.fullName } == ['refs/tags/tag1'] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /grgit-core/src/test/resources/org/ajoberstar/grgit/operation/sample.patch: -------------------------------------------------------------------------------- 1 | From 25e69680577d1c193f378c3eb5761de0209c7b94 Mon Sep 17 00:00:00 2001 2 | From: Andrew Oberstar 3 | Date: Sun, 29 Sep 2013 17:09:06 -0500 4 | Subject: [PATCH] Changes. 5 | 6 | --- 7 | 2.txt | 1 + 8 | 3.txt | 1 + 9 | 2 files changed, 2 insertions(+) 10 | create mode 100644 3.txt 11 | 12 | diff --git a/2.txt b/2.txt 13 | index 3dfdc59..c2e2e28 100644 14 | --- a/2.txt 15 | +++ b/2.txt 16 | @@ -1 +1,2 @@ 17 | something else 18 | +is being added 19 | diff --git a/3.txt b/3.txt 20 | new file mode 100644 21 | index 0000000..df5e072 22 | --- /dev/null 23 | +++ b/3.txt 24 | @@ -0,0 +1 @@ 25 | +some new stuff 26 | -- 27 | 1.8.1.2 28 | 29 | -------------------------------------------------------------------------------- /grgit-core/src/transform1/groovy/org/ajoberstar/grgit/internal/AnnotateAtRuntime.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.internal; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import org.codehaus.groovy.transform.GroovyASTTransformationClass; 9 | 10 | @Retention(RetentionPolicy.SOURCE) 11 | @Target(ElementType.TYPE) 12 | @GroovyASTTransformationClass("org.ajoberstar.grgit.internal.AnnotateAtRuntimeASTTransformation") 13 | public @interface AnnotateAtRuntime { 14 | String[] annotations() default {}; 15 | } 16 | -------------------------------------------------------------------------------- /grgit-core/src/transform1/groovy/org/ajoberstar/grgit/internal/AnnotateAtRuntimeASTTransformation.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.internal; 2 | 3 | import java.util.List; 4 | 5 | import org.codehaus.groovy.ast.ASTNode; 6 | import org.codehaus.groovy.ast.AnnotatedNode; 7 | import org.codehaus.groovy.ast.AnnotationNode; 8 | import org.codehaus.groovy.ast.ClassNode; 9 | import org.codehaus.groovy.control.SourceUnit; 10 | import org.codehaus.groovy.transform.AbstractASTTransformation; 11 | import org.codehaus.groovy.transform.GroovyASTTransformation; 12 | 13 | @GroovyASTTransformation 14 | public final class AnnotateAtRuntimeASTTransformation extends AbstractASTTransformation { 15 | @Override 16 | public void visit(ASTNode[] nodes, SourceUnit source) { 17 | AnnotationNode annotation = (AnnotationNode) nodes[0]; 18 | AnnotatedNode parent = (AnnotatedNode) nodes[1]; 19 | 20 | ClassNode clazz = (ClassNode) parent; 21 | List annotations = getMemberList(annotation, "annotations"); 22 | for (String name : annotations) { 23 | // !!! UGLY HACK !!! 24 | // Groovy won't think the class is an annotation when creating a ClassNode just based on the name. 25 | // Instead, we create a node based on an interface and then overwrite the name to get the interface 26 | // we actually want. 27 | ClassNode base = new ClassNode(FunctionalInterface.class); 28 | base.setName(name); 29 | 30 | clazz.addAnnotation(new AnnotationNode(base)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /grgit-core/src/transform2/groovy/org/ajoberstar/grgit/Configurable.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit 2 | 3 | import org.ajoberstar.grgit.internal.AnnotateAtRuntime 4 | 5 | @FunctionalInterface 6 | @AnnotateAtRuntime(annotations = "org.gradle.api.HasImplicitReceiver") 7 | interface Configurable { 8 | void configure(T t) 9 | } 10 | -------------------------------------------------------------------------------- /grgit-core/src/transform2/groovy/org/ajoberstar/grgit/internal/OpSyntax.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.internal 2 | 3 | import java.util.concurrent.Callable 4 | 5 | import org.ajoberstar.grgit.Configurable 6 | 7 | class OpSyntax { 8 | static def noArgOperation(Class opClass, Object[] classArgs) { 9 | def op = opClass.newInstance(classArgs) 10 | return op.call() 11 | } 12 | 13 | static def mapOperation(Class opClass, Object[] classArgs, Map args) { 14 | def op = opClass.newInstance(classArgs) 15 | 16 | args.forEach { key, value -> 17 | op[key] = value 18 | } 19 | 20 | return op.call() 21 | } 22 | 23 | static def samOperation(Class opClass, Object[] classArgs, Configurable arg) { 24 | def op = opClass.newInstance(classArgs) 25 | arg.configure(op) 26 | return op.call() 27 | } 28 | 29 | static def closureOperation(Class opClass, Object[] classArgs, Closure closure) { 30 | def op = opClass.newInstance(classArgs) 31 | 32 | Object originalDelegate = closure.delegate 33 | closure.delegate = op 34 | closure.resolveStrategy = Closure.DELEGATE_FIRST 35 | closure.call() 36 | closure.delegate = originalDelegate 37 | 38 | return op.call() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /grgit-core/src/transform2/groovy/org/ajoberstar/grgit/internal/Operation.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.internal; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.SOURCE) 9 | @Target(ElementType.TYPE) 10 | public @interface Operation { 11 | String value(); 12 | } 13 | -------------------------------------------------------------------------------- /grgit-core/src/transform2/groovy/org/ajoberstar/grgit/internal/WithOperations.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.internal; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.util.concurrent.Callable; 8 | 9 | import org.codehaus.groovy.transform.GroovyASTTransformationClass; 10 | 11 | @Retention(RetentionPolicy.SOURCE) 12 | @Target(ElementType.TYPE) 13 | @GroovyASTTransformationClass("org.ajoberstar.grgit.internal.WithOperationsASTTransformation") 14 | public @interface WithOperations { 15 | Class>[] staticOperations() default {}; 16 | 17 | Class>[] instanceOperations() default {}; 18 | } 19 | -------------------------------------------------------------------------------- /grgit-gradle/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.ajoberstar.defaults.gradle-plugin") 3 | id("groovy") 4 | 5 | id("org.ajoberstar.stutter") 6 | } 7 | 8 | group = "org.ajoberstar.grgit" 9 | description = "The Groovy way to use Git" 10 | 11 | mavenCentral { 12 | developerName.set("Andrew Oberstar") 13 | developerEmail.set("andrew@ajoberstar.org") 14 | githubOwner.set("ajoberstar") 15 | githubRepository.set("grgit") 16 | } 17 | 18 | java { 19 | toolchain { 20 | languageVersion.set(JavaLanguageVersion.of(11)) 21 | } 22 | } 23 | 24 | dependencies { 25 | api(project(":grgit-core")) { 26 | exclude(group = "org.codehaus.groovy") 27 | } 28 | compatTestImplementation(project(":grgit-core")) 29 | 30 | compatTestImplementation("org.spockframework:spock-core:2.3-groovy-3.0") 31 | } 32 | 33 | tasks.withType() { 34 | useJUnitPlatform() 35 | } 36 | 37 | tasks.named("jar") { 38 | manifest { 39 | attributes.put("Automatic-Module-Name", "org.ajoberstar.grgit.gradle") 40 | } 41 | } 42 | 43 | stutter { 44 | val java11 by matrices.creating { 45 | javaToolchain { 46 | languageVersion.set(JavaLanguageVersion.of(11)) 47 | } 48 | gradleVersions { 49 | compatibleRange("7.0") 50 | } 51 | } 52 | val java17 by matrices.creating { 53 | javaToolchain { 54 | languageVersion.set(JavaLanguageVersion.of(17)) 55 | } 56 | gradleVersions { 57 | compatibleRange("7.3") 58 | } 59 | } 60 | val java21 by matrices.creating { 61 | javaToolchain { 62 | languageVersion.set(JavaLanguageVersion.of(21)) 63 | } 64 | gradleVersions { 65 | compatibleRange("8.4") 66 | } 67 | } 68 | } 69 | 70 | tasks.named("check") { 71 | dependsOn(tasks.named("compatTest")) 72 | } 73 | 74 | gradlePlugin { 75 | plugins { 76 | create("grgitPlugin") { 77 | id = "org.ajoberstar.grgit" 78 | displayName = "The Groovy way to use Git" 79 | description = "The Groovy way to use Git" 80 | implementationClass = "org.ajoberstar.grgit.gradle.GrgitPlugin" 81 | } 82 | create("grgitServicePlugin") { 83 | id = "org.ajoberstar.grgit.service" 84 | displayName = "The Groovy way to use Git (BuildService edition)" 85 | description = "The Groovy way to use Git (BuildService edition)" 86 | implementationClass = "org.ajoberstar.grgit.gradle.GrgitServicePlugin" 87 | } 88 | } 89 | } 90 | 91 | tasks.withType { 92 | if (name.startsWith("compatTest")) { 93 | dependsOn(tasks.named("publishToMavenLocal")) 94 | dependsOn(project(":grgit-core").tasks.named("publishToMavenLocal")) 95 | systemProperty("compat.plugin.version", project.version.toString()) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /grgit-gradle/gradle.lockfile: -------------------------------------------------------------------------------- 1 | # This is a Gradle generated file for dependency locking. 2 | # Manual edits can break the build and are not advised. 3 | # This file is expected to be part of source control. 4 | com.googlecode.javaewah:JavaEWAH:1.2.3=compatTestCompileClasspath,compatTestRuntimeClasspath,compileClasspath,default,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 5 | commons-codec:commons-codec:1.16.0=default 6 | commons-codec:commons-codec:1.17.0=compatTestCompileClasspath,compatTestRuntimeClasspath,compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 7 | org.apiguardian:apiguardian-api:1.1.2=compatTestCompileClasspath 8 | org.codehaus.groovy:groovy:3.0.12=compatTestCompileClasspath,compatTestRuntimeClasspath 9 | org.eclipse.jgit:org.eclipse.jgit:6.10.0.202406032230-r=compatTestCompileClasspath,compatTestRuntimeClasspath,compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 10 | org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r=default 11 | org.hamcrest:hamcrest:2.2=compatTestCompileClasspath,compatTestRuntimeClasspath 12 | org.junit.platform:junit-platform-commons:1.9.0=compatTestCompileClasspath,compatTestRuntimeClasspath 13 | org.junit.platform:junit-platform-engine:1.9.0=compatTestCompileClasspath,compatTestRuntimeClasspath 14 | org.junit:junit-bom:5.9.0=compatTestCompileClasspath,compatTestRuntimeClasspath 15 | org.opentest4j:opentest4j:1.2.0=compatTestCompileClasspath,compatTestRuntimeClasspath 16 | org.slf4j:slf4j-api:1.7.36=compatTestCompileClasspath,compatTestRuntimeClasspath,compileClasspath,default,runtimeClasspath,testCompileClasspath,testRuntimeClasspath 17 | org.spockframework:spock-core:2.3-groovy-3.0=compatTestCompileClasspath,compatTestRuntimeClasspath 18 | empty=annotationProcessor,archives,compatTestAnnotationProcessor,signatures,testAnnotationProcessor 19 | -------------------------------------------------------------------------------- /grgit-gradle/src/compatTest/groovy/org/ajoberstar/grgit/gradle/GrgitPluginCompatTest.groovy: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.gradle 2 | 3 | import spock.lang.Specification 4 | 5 | import org.ajoberstar.grgit.Grgit 6 | import org.gradle.testkit.runner.GradleRunner 7 | import org.gradle.testkit.runner.BuildResult 8 | import org.gradle.testkit.runner.TaskOutcome 9 | import spock.lang.TempDir 10 | 11 | class GrgitPluginCompatTest extends Specification { 12 | @TempDir File tempDir 13 | File projectDir 14 | File settingsFile 15 | File buildFile 16 | 17 | def setup() { 18 | projectDir = new File(tempDir, 'project') 19 | settingsFile = projectFile('settings.gradle') 20 | buildFile = projectFile('build.gradle') 21 | 22 | settingsFile << """\ 23 | pluginManagement { 24 | repositories { 25 | mavenCentral() 26 | mavenLocal() 27 | } 28 | plugins { 29 | id 'org.ajoberstar.grgit' version '${System.properties['compat.plugin.version']}\' 30 | } 31 | } 32 | """ 33 | } 34 | 35 | def 'with no repo, plugin sets grgit to null'() { 36 | given: 37 | buildFile << '''\ 38 | plugins { 39 | id 'org.ajoberstar.grgit' 40 | } 41 | 42 | task doStuff { 43 | doLast { 44 | assert grgit == null 45 | } 46 | } 47 | ''' 48 | when: 49 | def result = build('doStuff', '--no-configuration-cache') 50 | then: 51 | result.task(':doStuff').outcome == TaskOutcome.SUCCESS 52 | } 53 | 54 | def 'with repo, plugin opens the repo as grgit'() { 55 | given: 56 | Grgit git = Grgit.init(dir: projectDir) 57 | projectFile('1.txt') << '1' 58 | git.add(patterns: ['1.txt']) 59 | git.commit(message: 'yay') 60 | git.tag.add(name: '1.0.0') 61 | 62 | buildFile << '''\ 63 | plugins { 64 | id 'org.ajoberstar.grgit' 65 | } 66 | 67 | task doStuff { 68 | doLast { 69 | println grgit.describe() 70 | } 71 | } 72 | ''' 73 | when: 74 | def result = build('doStuff', '--quiet', '--no-configuration-cache') 75 | then: 76 | result.task(':doStuff').outcome == TaskOutcome.SUCCESS 77 | result.output.normalize() == '1.0.0\n' 78 | } 79 | 80 | def 'with repo, plugin closes the repo after build is finished'() { 81 | given: 82 | Grgit git = Grgit.init(dir: projectDir) 83 | projectFile('1.txt') << '1' 84 | git.add(patterns: ['1.txt']) 85 | git.commit(message: 'yay') 86 | git.tag.add(name: '1.0.0') 87 | 88 | buildFile << '''\ 89 | plugins { 90 | id 'org.ajoberstar.grgit' 91 | } 92 | 93 | task doStuff { 94 | doLast { 95 | println grgit.describe() 96 | } 97 | } 98 | ''' 99 | when: 100 | def result = build('doStuff', '--info', '--no-configuration-cache') 101 | then: 102 | result.task(':doStuff').outcome == TaskOutcome.SUCCESS 103 | result.output.contains('Closing Git repo') 104 | } 105 | 106 | private BuildResult build(String... args) { 107 | return GradleRunner.create() 108 | .withGradleVersion(System.properties['compat.gradle.version']) 109 | .withProjectDir(projectDir) 110 | .forwardOutput() 111 | .withArguments((args + '--stacktrace') as String[]) 112 | .build() 113 | } 114 | 115 | private File projectFile(String path) { 116 | File file = new File(projectDir, path) 117 | file.parentFile.mkdirs() 118 | return file 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /grgit-gradle/src/main/java/org/ajoberstar/grgit/gradle/GrgitPlugin.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.gradle; 2 | 3 | import org.ajoberstar.grgit.Grgit; 4 | import org.gradle.api.Plugin; 5 | import org.gradle.api.Project; 6 | import org.gradle.api.provider.Provider; 7 | 8 | /** 9 | * Plugin adding a {@code grgit} property to all projects that searches for a Git repo from the 10 | * project's directory. 11 | * 12 | * @since 2.0.0 13 | */ 14 | public class GrgitPlugin implements Plugin { 15 | @Override 16 | public void apply(Project project) { 17 | project.getPluginManager().apply(GrgitServicePlugin.class); 18 | var serviceExtension = project.getExtensions().getByType(GrgitServiceExtension.class); 19 | try { 20 | project.getLogger().info("The org.ajoberstar.grgit plugin eagerly opens a Grgit instance. Use org.ajoberstar.grgit.service for better performance."); 21 | project.getExtensions().add(Grgit.class, "grgit", serviceExtension.getService().get().getGrgit()); 22 | } catch (Exception e) { 23 | project.getLogger().debug("Failed to open Grgit instance", e); 24 | project.getExtensions().getExtraProperties().set("grgit", null); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /grgit-gradle/src/main/java/org/ajoberstar/grgit/gradle/GrgitService.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.gradle; 2 | 3 | import java.io.File; 4 | import java.util.Optional; 5 | 6 | import javax.inject.Inject; 7 | 8 | import org.ajoberstar.grgit.Grgit; 9 | import org.gradle.api.file.DirectoryProperty; 10 | import org.gradle.api.logging.Logger; 11 | import org.gradle.api.logging.Logging; 12 | import org.gradle.api.provider.Property; 13 | import org.gradle.api.provider.ProviderFactory; 14 | import org.gradle.api.services.BuildService; 15 | import org.gradle.api.services.BuildServiceParameters; 16 | 17 | public abstract class GrgitService implements BuildService, AutoCloseable { 18 | private static final Logger logger = Logging.getLogger(GrgitService.class); 19 | 20 | public interface Params extends BuildServiceParameters { 21 | DirectoryProperty getCurrentDirectory(); 22 | 23 | DirectoryProperty getDirectory(); 24 | 25 | Property getInitIfNotExists(); 26 | } 27 | 28 | @Inject 29 | public GrgitService(ProviderFactory providers) { 30 | getGrgitProperty().set(providers.provider(this::makeGrgit)); 31 | getGrgitProperty().disallowChanges(); 32 | getGrgitProperty().finalizeValueOnRead(); 33 | } 34 | 35 | protected abstract Property getGrgitProperty(); 36 | 37 | public Grgit getGrgit() { 38 | return getGrgitProperty().get(); 39 | } 40 | 41 | public Optional findGrgit() { 42 | try { 43 | return Optional.of(getGrgit()); 44 | } catch (Exception e) { 45 | logger.info("Failed to make grgit service.", e); 46 | return Optional.empty(); 47 | } 48 | } 49 | 50 | @Override 51 | public void close() throws Exception { 52 | findGrgit().ifPresent(grgit -> { 53 | logger.info("Closing Git repo: {}", grgit.getRepository().getRootDir()); 54 | grgit.close(); 55 | }); 56 | } 57 | 58 | private Grgit makeGrgit() { 59 | if (getParameters().getCurrentDirectory().isPresent()) { 60 | return Grgit.open(op -> { 61 | op.setCurrentDir(getParameters().getCurrentDirectory().get().getAsFile()); 62 | }); 63 | } 64 | 65 | var dir = getParameters().getDirectory().get().getAsFile(); 66 | var gitDir = new File(dir, ".git"); 67 | if (gitDir.exists()) { 68 | return Grgit.open(op -> { 69 | op.setDir(dir); 70 | }); 71 | } else if (getParameters().getInitIfNotExists().getOrElse(false)) { 72 | return Grgit.init(op -> { 73 | op.setDir(dir); 74 | }); 75 | } else { 76 | throw new IllegalStateException("No Git repo exists at " + dir + " and initIfNotExists is false. Cannot proceed."); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /grgit-gradle/src/main/java/org/ajoberstar/grgit/gradle/GrgitServiceExtension.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.gradle; 2 | 3 | import org.gradle.api.provider.Provider; 4 | 5 | public class GrgitServiceExtension { 6 | private final Provider service; 7 | 8 | public GrgitServiceExtension(Provider service) { 9 | this.service = service; 10 | } 11 | 12 | public Provider getService() { 13 | return service; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /grgit-gradle/src/main/java/org/ajoberstar/grgit/gradle/GrgitServicePlugin.java: -------------------------------------------------------------------------------- 1 | package org.ajoberstar.grgit.gradle; 2 | 3 | import org.gradle.api.Plugin; 4 | import org.gradle.api.Project; 5 | import org.gradle.api.provider.Provider; 6 | 7 | public class GrgitServicePlugin implements Plugin { 8 | @Override 9 | public void apply(Project project) { 10 | Provider serviceProvider = project.getGradle().getSharedServices().registerIfAbsent("grgit", GrgitService.class, spec -> { 11 | spec.getParameters().getCurrentDirectory().set(project.getLayout().getProjectDirectory()); 12 | spec.getMaxParallelUsages().set(1); 13 | }); 14 | 15 | project.getExtensions().create("grgitService", GrgitServiceExtension.class, serviceProvider); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /grgit-gradle/stutter.lockfile: -------------------------------------------------------------------------------- 1 | # DO NOT MODIFY: Generated by Stutter plugin. 2 | java11=7.0.2,7.6.4,8.0.2,8.10.2 3 | java17=7.3.3,7.6.4,8.0.2,8.10.2 4 | java21=8.4,8.10.2 5 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | plugins { 3 | id("org.ajoberstar.defaults.java-library") version "0.18.0" 4 | id("org.ajoberstar.defaults.gradle-plugin") version "0.18.0" 5 | 6 | id("org.ajoberstar.reckon.settings") version "0.19.2" 7 | id("org.ajoberstar.stutter") version "1.0.0" 8 | 9 | id("com.diffplug.spotless") version "7.0.3" 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | } 16 | 17 | plugins { 18 | id("org.ajoberstar.reckon.settings") 19 | } 20 | 21 | extensions.configure { 22 | setDefaultInferredScope("patch") 23 | stages("beta", "rc", "final") 24 | setScopeCalc(calcScopeFromProp().or(calcScopeFromCommitMessages())) 25 | setStageCalc(calcStageFromProp()) 26 | } 27 | 28 | dependencyResolutionManagement { 29 | repositories { 30 | mavenCentral() 31 | } 32 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 33 | } 34 | 35 | rootProject.name = "grgit" 36 | 37 | include("grgit-core") 38 | include("grgit-gradle") 39 | --------------------------------------------------------------------------------