Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: added support for dirty files #368

Merged
merged 11 commits into from
Sep 18, 2023
19 changes: 19 additions & 0 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ commitAuthor:
commitMessage: "chore(release): this is a custom release message"
```

## DirtyFiles
```{ .yaml .annotate linenums="1" }
# Allowing specific case sensitive files to allow using uplift to
# add unedited but changed files as part of your CI
ga-shoaib-w marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is clear enough what the feature does, maybe an example of why it would be useful?
I also think we should update faq/gitdirty.md with how this feature can help.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will rewrite


git:
dirtyFiles:
- file.txt
- path/to/file.txt
```

ga-shoaib-w marked this conversation as resolved.
Show resolved Hide resolved
## hooks

```{ .yaml .annotate linenums="1" }
Expand Down Expand Up @@ -242,6 +253,14 @@ git:
- option: ci.variable="MAX_RETRIES=10"
skipTag: true
skipBranch: false

# Defines a list of files that uplift will ignore when checking the
# status of the current repository. If a change is detected that is
# not defined in this list, uplift will assume its default behaviour
# and fail due to the repository being in a dirty state
dirtyFiles:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've generally found this change hard to understand from the naming and documentation. The text does not really tell me what happens with the 'dirtyFiles' are they only ignored or are they staged / committed by uplift. My assumption is that you want the Uplift to stage the files otherwise you could just add them to the .gitignore file? I feel the name of this config should describe what you want uplift to do with them. So if completely ignoring then maybe ignoreFiles, if staging then maybe stageFiles or addFiles or includeArtifacts (thinking build artifacts that you want in a 'release').

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the name includeArtifacts - renaming it

- file.txt

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow Glob patterns? Can this be added later without breaking compatibility?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldnt like to introduce Glob patterns - only explicit files should only be allowed so users are aware of any extra files which shouldnt have changed

- path/to/file.txt
```

## gitea
Expand Down
8 changes: 8 additions & 0 deletions docs/static/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@
},
"type": "array",
"minItems": 1
},
"dirtyFiles": {
"items": {
"$comment": "https://upliftci.dev/reference/config#git",
"description": "Defines a list of files that uplift will ignore when checking the status of the current repository. If a change is detected that is not defined in this list, uplift will assume its default behaviour and fail due to the repository being in a dirty state"
},
"type": "array",
"minItems": 1
}
},
"type": "object",
Expand Down
1 change: 1 addition & 0 deletions internal/config/uplift.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ type Git struct {
IgnoreDetached bool `yaml:"ignoreDetached"`
IgnoreShallow bool `yaml:"ignoreShallow"`
PushOptions []GitPushOption `yaml:"pushOptions" validate:"dive"`
DirtyFiles []string `yaml:"dirtyFiles" validate:"omitempty,dive,min=1,file"`
}

// GitPushOption provides a way of supplying additional options to
Expand Down
11 changes: 11 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Context struct {
CommitDetails git.CommitDetails
Config config.Uplift
CurrentVersion semver.Version
DirtyFiles []string
DryRun bool
Debug bool
FetchTags bool
Expand Down Expand Up @@ -107,5 +108,15 @@ func New(cfg config.Uplift, out io.Writer) *Context {
SCM: SCM{
Provider: Unrecognised,
},
DirtyFiles: DirtyFiles(cfg),
}
}

// For nil safe object getting
func DirtyFiles(c config.Uplift) []string {
if c.Git == nil {
return nil
}

return c.Git.DirtyFiles
}
25 changes: 18 additions & 7 deletions internal/task/gitcheck/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ SOFTWARE.
package gitcheck

import (
"strings"

"github.com/apex/log"
"github.com/gembaadvantage/uplift/internal/context"
)
Expand Down Expand Up @@ -52,18 +50,22 @@ func (t Task) Run(ctx *context.Context) error {

log.Debug("checking if repository is dirty")
status, err := ctx.GitClient.PorcelainStatus()

if err != nil {
return err
}

if len(status) > 0 {
// Convert status into string friendly output
out := make([]string, 0, len(status))
for _, s := range status {
out = append(out, s.String())

if len(ctx.DirtyFiles) == 0 {
return ErrDirty{status}
}

return ErrDirty{status: strings.Join(out, "\n")}
for _, sts := range status {
if !stringInSlice(sts.Path, ctx.DirtyFiles) {
return ErrDirty{status}
}
}
}

log.Debug("checking for detached head")
Expand All @@ -86,3 +88,12 @@ func (t Task) Run(ctx *context.Context) error {

return nil
}

func stringInSlice(stringToFind string, listOfStrings []string) bool {
for _, value := range listOfStrings {
if value == stringToFind {
return true
}
}
return false
}
11 changes: 10 additions & 1 deletion internal/task/gitcheck/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,18 @@ func TestRun_Dirty(t *testing.T) {

err := Task{}.Run(&context.Context{})
assert.EqualError(t, err, `uplift cannot reliably run if the repository is in a dirty state. Changes detected:
?? testing.go
[?? testing.go]

Please check and resolve the status of these files before retrying. For further
details visit: https://upliftci.dev/faq/gitdirty
`)
}

func TestRun_DirtyWithConfiguredFiles(t *testing.T) {
gittest.InitRepository(t, gittest.WithFiles("testing.go"))

err := Task{}.Run(&context.Context{
DirtyFiles: []string{"testing.go"},
})
assert.NoError(t, err)
}
4 changes: 3 additions & 1 deletion internal/task/gitcheck/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ package gitcheck
import (
"errors"
"fmt"

git "github.com/purpleclay/gitz"
)

// ErrDirty is raised when a git repository has un-committed and/or un-staged changes
type ErrDirty struct {
status string
status []git.FileStatus
}

// Error returns a formatted message of the current error
Expand Down