Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions EMBEDDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,3 @@ The fragments can also be used in other languages:
</body>
</html>
```

### Providing fragments directly

It is possible to add the desired fragment file with exactly the required content
directly to the fragments folder, for example: `FRAGMENTS/desired-path/MyFile.kt`.

It can then be embedded just like any other fragment file:
```markdown
<embed-code file="desired-path/MyFile.kt"></embed-code>
```
16 changes: 3 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ The available arguments are:
* `-code-path`: (Optional) Path to the source code root directory.
* `-docs-path`: (Optional) Path to the documentation root directory.
* `-config-path`: (Optional) Path to a YAML configuration file containing `code-path` and `docs-path`.
* `-code-includes`: (Optional) Comma-separated glob patterns for source files to include (e.g., `"**/*.java,**/*.gradle"`). Defaults to `"**/*.*"`.
* `-code-excludes`: (Optional) Comma-separated glob patterns for source files to exclude.
* `-doc-includes`: (Optional) Comma-separated glob patterns for documentation files to include. Defaults to `"**/*.md,**/*.html"`.
* `-fragments-path`: (Optional) Directory for storing code fragments. Defaults to `./build/fragments`.
* `-separator`: (Optional) String used to separate joined code fragments. Defaults to `...`.

Even though the `code-path`, `docs-path`, and `config-path` arguments are optional,
Expand All @@ -87,7 +84,6 @@ Optional settings can be defined in a YAML configuration file:
```yaml
code-path: path/to/code/root
docs-path: path/to/docs/root
code-includes: "**/*.java,**/*.gradle"
doc-excludes: "**/*-old.*,**/deprecated/*.*"
```

Expand All @@ -98,7 +94,6 @@ embeddings:
- name: java
code-path: path/to/code/root/java
docs-path: path/to/java/docs
code-includes: "**/*.java"
- name: kotlin
code-path:
- name: samples
Expand Down Expand Up @@ -131,20 +126,15 @@ The available fields for the configuration file are:
```
**Do not forget the dollar sign (`$`) before the path name.**

It is possible to specify a path without a name or with an empty name.
In this case, fragments will be stored in the root defined by `fragments-path`.

It is also possible to specify multiple paths with the same name,
but this may lead to fragments being overwritten if they have the same relative path and name.
Code source names must be unique. A configuration may use either one unnamed
code source or one or more named code sources, but named and unnamed sources
cannot be mixed.

* `docs-path`: (Mandatory) Path to the documentation root.
* `code-includes`: (Optional) Glob patterns for source files to include.
It may be represented as a comma-separated string list or as a YAML sequence.
* `doc-excludes`: (Optional) Glob patterns for documentation files to exclude.
It may be represented as a comma-separated string list or as a YAML sequence.
* `doc-includes`: (Optional) Glob patterns for documentation files to include.
It may be represented as a comma-separated string list or as a YAML sequence.
* `fragments-path`: (Optional) Directory for code fragments.
* `separator`: (Optional) Separator for fragments.
* `embeddings`: (Optional) A list of complete embedding configurations for multiple
documentation targets. When `embeddings` is set, do not set root-level `code-path`
Expand Down
68 changes: 9 additions & 59 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ import (
_type "embed-code/embed-code-go/type"
"flag"
"os"
"path/filepath"
"strings"

"embed-code/embed-code-go/analyzing"
"embed-code/embed-code-go/configuration"
"embed-code/embed-code-go/embedding"
"embed-code/embed-code-go/fragmentation"

"gopkg.in/yaml.v3"
)
Expand All @@ -39,12 +37,6 @@ import (
//
// BaseDocsPath — a path to a root directory with docs files.
//
// CodeIncludes — a StringList with patterns for filtering the code files
// to be considered.
// Directories are never matched by these patterns.
// For example, "**/*.java,**/*.gradle".
// The default value is "**/*.*".
//
// DocIncludes — a StringList with patterns for filtering files
// in which we should look for embedding instructions.
// The patterns are resolved relatively to the `documentation_root`.
Expand All @@ -55,9 +47,6 @@ import (
// DocExcludes - a StringList with patterns for filtering documentation files
// which should be excluded from the embedding process.
//
// FragmentsPath — a directory where fragmented code is stored. A temporary directory that should
// not be tracked in VCS. The default value is: "./build/fragments".
//
// Separator — a string that's inserted between multiple partitions of a single fragment.
// The default value is "...".
//
Expand All @@ -73,10 +62,8 @@ import (
type Config struct {
BaseCodePaths _type.NamedPathList `yaml:"code-path"`
BaseDocsPath string `yaml:"docs-path"`
CodeIncludes _type.StringList `yaml:"code-includes"`
DocIncludes _type.StringList `yaml:"doc-includes"`
DocExcludes _type.StringList `yaml:"doc-excludes"`
FragmentsPath string `yaml:"fragments-path"`
Separator string `yaml:"separator"`
Embeddings []EmbeddingConfig `yaml:"embeddings"`
Info bool `yaml:"info"`
Expand All @@ -87,23 +74,18 @@ type Config struct {

// EmbeddingConfig contains a complete configuration for one embedding target.
type EmbeddingConfig struct {
Name string `yaml:"name"`
CodePaths _type.NamedPathList `yaml:"code-path"`
DocsPath string `yaml:"docs-path"`
CodeIncludes _type.StringList `yaml:"code-includes"`
DocIncludes _type.StringList `yaml:"doc-includes"`
DocExcludes _type.StringList `yaml:"doc-excludes"`
FragmentsPath string `yaml:"fragments-path"`
Separator string `yaml:"separator"`
Name string `yaml:"name"`
CodePaths _type.NamedPathList `yaml:"code-path"`
DocsPath string `yaml:"docs-path"`
DocIncludes _type.StringList `yaml:"doc-includes"`
DocExcludes _type.StringList `yaml:"doc-excludes"`
Separator string `yaml:"separator"`
}

// EmbedCodeSamplesResult is result of the EmbedCodeSamples method.
//
// WriteFragmentFilesResult the result of code fragmentation.
//
// EmbedAllResult the result of embedding code fragments in the documentation.
type EmbedCodeSamplesResult struct {
fragmentation.WriteFragmentFilesResult
embedding.EmbedAllResult
}

Expand All @@ -113,24 +95,19 @@ const (
ModeAnalyze = "analyze"
)

// CheckCodeSamples checks documentation to be up-to-date with code files. Raises
// UnexpectedDiffError if not.
// CheckCodeSamples returns documentation files that are not up-to-date with code files.
//
// config — a configuration for checking code samples.
func CheckCodeSamples(config configuration.Configuration) {
fragmentation.WriteFragmentFiles(config)
embedding.CheckUpToDate(config)
func CheckCodeSamples(config configuration.Configuration) []string {
return embedding.CheckUpToDate(config)
}

// EmbedCodeSamples embeds code fragments in documentation files.
//
// config — a configuration for embedding.
func EmbedCodeSamples(config configuration.Configuration) EmbedCodeSamplesResult {
fragmentationResult := fragmentation.WriteFragmentFiles(config)
embeddingResult := embedding.EmbedAll(config)
embedding.CheckUpToDate(config)
return EmbedCodeSamplesResult{
fragmentationResult,
embeddingResult,
}
}
Expand All @@ -139,9 +116,7 @@ func EmbedCodeSamples(config configuration.Configuration) EmbedCodeSamplesResult
//
// config — a configuration for embedding.
func AnalyzeCodeSamples(config configuration.Configuration) {
fragmentation.WriteFragmentFiles(config)
analyzing.AnalyzeAll(config)
fragmentation.CleanFragmentFiles(config)
}

// ReadArgs reads user-specified args from the command line.
Expand All @@ -150,14 +125,10 @@ func AnalyzeCodeSamples(config configuration.Configuration) {
func ReadArgs() Config {
codePath := flag.String("code-path", "", "a path to a root directory with code files")
docsPath := flag.String("docs-path", "", "a path to a root directory with docs files")
codeIncludes := flag.String("code-includes", "",
"a comma-separated string of glob patterns for code files to include")
docIncludes := flag.String("doc-includes", "",
"a comma-separated string of glob patterns for docs files to include")
docExcludes := flag.String("doc-excludes", "",
"a comma-separated string of glob patterns for docs files to exclude")
fragmentsPath := flag.String("fragments-path", "",
"a path to a directory where fragmented code is stored")
separator := flag.String("separator", "",
"a string that's inserted between multiple partitions of a single fragment")
configPath := flag.String("config-path", "", "a path to a yaml configuration file")
Expand All @@ -173,10 +144,8 @@ func ReadArgs() Config {
return Config{
BaseCodePaths: _type.NamedPathList{_type.NamedPath{Path: *codePath}},
BaseDocsPath: *docsPath,
CodeIncludes: parseListArgument(*codeIncludes),
DocIncludes: parseListArgument(*docIncludes),
DocExcludes: parseListArgument(*docExcludes),
FragmentsPath: *fragmentsPath,
Separator: *separator,
ConfigPath: *configPath,
Mode: *mode,
Expand All @@ -195,9 +164,6 @@ func FillArgsFromConfigFile(args Config) (Config, error) {
args.BaseDocsPath = configFields.BaseDocsPath
args.BaseCodePaths = configFields.BaseCodePaths

if len(configFields.CodeIncludes) > 0 {
args.CodeIncludes = configFields.CodeIncludes
}
if len(configFields.Embeddings) > 0 {
args.Embeddings = configFields.Embeddings
}
Expand All @@ -207,9 +173,6 @@ func FillArgsFromConfigFile(args Config) (Config, error) {
if len(configFields.DocExcludes) > 0 {
args.DocExcludes = configFields.DocExcludes
}
if isNotEmpty(configFields.FragmentsPath) {
args.FragmentsPath = configFields.FragmentsPath
}
if isNotEmpty(configFields.Separator) {
args.Separator = configFields.Separator
}
Expand Down Expand Up @@ -248,19 +211,12 @@ func configFromEmbedding(embedding EmbeddingConfig) configuration.Configuration
embedCodeConfig.CodeRoots = embedding.CodePaths
embedCodeConfig.DocumentationRoot = embedding.DocsPath

if len(embedding.CodeIncludes) > 0 {
embedCodeConfig.CodeIncludes = embedding.CodeIncludes
}
if len(embedding.DocIncludes) > 0 {
embedCodeConfig.DocIncludes = embedding.DocIncludes
}
if len(embedding.DocExcludes) > 0 {
embedCodeConfig.DocExcludes = embedding.DocExcludes
}
if isNotEmpty(embedding.FragmentsPath) {
embedCodeConfig.FragmentsDir = embedding.FragmentsPath
}
embedCodeConfig.FragmentsDir = filepath.Join(embedCodeConfig.FragmentsDir, embedding.Name)
if isNotEmpty(embedding.Separator) {
embedCodeConfig.Separator = embedding.Separator
}
Expand All @@ -272,15 +228,9 @@ func configFromEmbedding(embedding EmbeddingConfig) configuration.Configuration
func configWithOptionalParams(userArgs Config) configuration.Configuration {
embedCodeConfig := configuration.NewConfiguration()

if len(userArgs.CodeIncludes) > 0 {
embedCodeConfig.CodeIncludes = userArgs.CodeIncludes
}
if len(userArgs.DocIncludes) > 0 {
embedCodeConfig.DocIncludes = userArgs.DocIncludes
}
if isNotEmpty(userArgs.FragmentsPath) {
embedCodeConfig.FragmentsDir = userArgs.FragmentsPath
}
if isNotEmpty(userArgs.Separator) {
embedCodeConfig.Separator = userArgs.Separator
}
Expand Down
74 changes: 50 additions & 24 deletions cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package cli_test

import (
"embed-code/embed-code-go/cli"
"embed-code/embed-code-go/configuration"
_type "embed-code/embed-code-go/type"
"os"
"path/filepath"
Expand Down Expand Up @@ -76,20 +75,6 @@ var _ = Describe("CLI validation", func() {
Expect(cli.ValidateConfig(config)).Error().ShouldNot(HaveOccurred())
})

It("should store embedding fragments under a named subfolder", func() {
embedding := baseEmbeddingConfig()
embedding.FragmentsPath = "/tmp/fragments"
config := cli.Config{
Mode: cli.ModeCheck,
Embeddings: []cli.EmbeddingConfig{embedding},
}

embedConfigs := cli.BuildEmbedCodeConfiguration(config)

Expect(embedConfigs).To(HaveLen(1))
Expect(embedConfigs[0].Name).To(Equal("docs"))
Expect(embedConfigs[0].FragmentsDir).To(Equal(filepath.Join("/tmp/fragments", "docs")))
})
})

Context("with invalid config", func() {
Expand Down Expand Up @@ -155,9 +140,9 @@ var _ = Describe("CLI validation", func() {

It("should fail validation when embeddings and root optional params are set at the same time", func() {
invalidConfig := cli.Config{
Mode: cli.ModeCheck,
CodeIncludes: []string{"**/*.java"},
Embeddings: []cli.EmbeddingConfig{baseEmbeddingConfig()},
Mode: cli.ModeCheck,
DocIncludes: []string{"**/*.md"},
Embeddings: []cli.EmbeddingConfig{baseEmbeddingConfig()},
}

Expect(cli.ValidateConfig(invalidConfig)).Error().Should(HaveOccurred())
Expand Down Expand Up @@ -190,6 +175,42 @@ var _ = Describe("CLI validation", func() {
"duplicate embedding names detected:\n- docs"))
})

It("should fail validation when source code path names are duplicated", func() {
invalidConfig := baseCliConfig()
invalidConfig.BaseCodePaths = _type.NamedPathList{
_type.NamedPath{Name: "samples", Path: codeResourcePath("java")},
_type.NamedPath{Name: "samples", Path: codeResourcePath("kotlin")},
}

Expect(cli.ValidateConfig(invalidConfig)).Error().Should(HaveOccurred())
Expect(cli.ValidateConfig(invalidConfig).Error()).Should(Equal(
"duplicate source code path names detected:\n- samples"))
})

It("should fail validation when multiple unnamed sources code paths are configured", func() {
invalidConfig := baseCliConfig()
invalidConfig.BaseCodePaths = _type.NamedPathList{
_type.NamedPath{Path: codeResourcePath("java")},
_type.NamedPath{Path: codeResourcePath("kotlin")},
}

Expect(cli.ValidateConfig(invalidConfig)).Error().Should(HaveOccurred())
Expect(cli.ValidateConfig(invalidConfig).Error()).Should(Equal(
"only one unnamed source code path is allowed"))
})

It("should fail validation when named and unnamed source code paths are mixed", func() {
invalidConfig := baseCliConfig()
invalidConfig.BaseCodePaths = _type.NamedPathList{
_type.NamedPath{Name: "java", Path: codeResourcePath("java")},
_type.NamedPath{Path: codeResourcePath("kotlin")},
}

Expect(cli.ValidateConfig(invalidConfig)).Error().Should(HaveOccurred())
Expect(cli.ValidateConfig(invalidConfig).Error()).Should(Equal(
"named and unnamed source code paths cannot be mixed"))
})

It("should correctly convert embeddings to a few configs", func() {
config := cli.Config{
Mode: cli.ModeCheck,
Expand All @@ -204,18 +225,12 @@ var _ = Describe("CLI validation", func() {
Expect(embedConfigs[0].Name).To(Equal("java"))
Expect(embedConfigs[0].CodeRoots[0].Path).To(Equal("test/resources/code/java"))
Expect(embedConfigs[0].DocumentationRoot).To(Equal("test/resources/docs"))
Expect(embedConfigs[0].FragmentsDir).To(Equal(
filepath.Join(configuration.DefaultFragmentsDir, "java")))
Expect(embedConfigs[1].Name).To(Equal("kotlin"))
Expect(embedConfigs[1].CodeRoots[0].Path).To(Equal("test/resources/code/kotlin"))
Expect(embedConfigs[1].DocumentationRoot).To(Equal("test/resources/docs/nested-dir-1"))
Expect(embedConfigs[1].FragmentsDir).To(Equal(
filepath.Join(configuration.DefaultFragmentsDir, "kotlin")))
Expect(embedConfigs[2].Name).To(Equal("nested-java"))
Expect(embedConfigs[2].DocumentationRoot).To(
Equal("test/resources/docs/nested-dir-1/nested-dir-3"))
Expect(embedConfigs[2].FragmentsDir).To(Equal(
filepath.Join(configuration.DefaultFragmentsDir, "nested-java")))
Expect(embedConfigs[2].Separator).To(Equal("---"))
})

Expand Down Expand Up @@ -255,3 +270,14 @@ func configFilePath() string {

return parentDir + "/test/resources/config_files/correct_config.yml"
}

// codeResourcePath builds an absolute path to a test source-code fixture directory.
func codeResourcePath(name string) string {
currentDir, err := os.Getwd()
if err != nil {
panic(err)
}
parentDir := filepath.Dir(currentDir)

return filepath.Join(parentDir, "test/resources/code", name)
}
Loading
Loading