diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index e654a3b..d1c2bef 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -40,29 +40,12 @@ jobs: - name: "Run go build" run: "go build" - mirror-gitlab-job: - runs-on: "ubuntu-22.04" - steps: - - name: "Check out repository" - uses: "actions/checkout@v4.1.6" - with: - fetch-depth: 0 - - name: "Add Gitlab Remote" - run: | - git remote add gitlab https://oauth2:${{ secrets.GITLAB_LABDOC_MIRROR_TOKEN }}@gitlab.com/erNail/labdoc.git - - name: "Push all branches to GitLab" - run: "git push gitlab --all --force" - - - name: "Push all tags to GitLab" - run: "git push gitlab --tags --force" - release-job: runs-on: "ubuntu-22.04" needs: - "go-test-job" - "go-build-job" - "pre-commit-job" - - "mirror-gitlab-job" permissions: contents: "write" steps: @@ -95,4 +78,22 @@ jobs: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" DOCKER_LABDOC_GORELEASER_TOKEN: "${{ secrets.DOCKER_LABDOC_GORELEASER_TOKEN }}" HOMEBREW_TAP_ERNAIL_GITHUB_TOKEN: "${{ secrets.HOMEBREW_TAP_ERNAIL_GITHUB_TOKEN }}" + + mirror-gitlab-job: + runs-on: "ubuntu-22.04" + needs: + - "release-job" + steps: + - name: "Check out repository" + uses: "actions/checkout@v4.1.6" + with: + fetch-depth: 0 + - name: "Add Gitlab Remote" + run: | + git remote add gitlab https://oauth2:${{ secrets.GITLAB_LABDOC_MIRROR_TOKEN }}@gitlab.com/erNail/labdoc.git + - name: "Push all branches to GitLab" + run: "git push gitlab --all --force" + + - name: "Push all tags to GitLab" + run: "git push gitlab --tags --force" ... diff --git a/go.sum b/go.sum index 11373f6..d969cb2 100644 --- a/go.sum +++ b/go.sum @@ -20,11 +20,9 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= diff --git a/internal/gitlab/component_documentation_test.go b/internal/gitlab/component_documentation_test.go index 069ef3e..0fb4a12 100644 --- a/internal/gitlab/component_documentation_test.go +++ b/internal/gitlab/component_documentation_test.go @@ -8,41 +8,201 @@ import ( "github.com/stretchr/testify/require" ) -func TestGenerateDocumentationUsesEmbeddedTemplate(t *testing.T) { +func TestGenerateDocumentationRendersInputTableCorrectly(t *testing.T) { + t.Parallel() + + componentContent := `--- +# Component Description +spec: + inputs: + string-with-default: + type: "string" + default: "" + string-without-default: + type: "string" + array-with-default: + type: "array" + default: [] + array-without-default: + type: "array" + boolean-with-default: + type: "boolean" + default: false + boolean-without-default: + type: "boolean" + number-with-default: + type: "number" + default: 0 + number-without-default: + type: "number" + string-with-options: + type: "string" + options: + - "one" + - "two" + string-with-regex: + type: "string" + regex: "^test." + input-with-description-only: + description: "Input with description only" + input-with-default-only: + default: [] + input-without-anything: {} +... +` + + expectedMarkdownTable := "\n" + + "| Name | Description | Type | Default | Options | Regex | Mandatory |\n" + + "|------|-------------|------|---------|---------|-------|-----------|\n" + + "| `array-with-default` | | `array` | `[]` | `-` | `-` | No |\n" + + "| `array-without-default` | | `array` | `-` | `-` | `-` | Yes |\n" + + "| `boolean-with-default` | | `boolean` | `false` | `-` | `-` | No |\n" + + "| `boolean-without-default` | | `boolean` | `-` | `-` | `-` | Yes |\n" + + "| `input-with-default-only` | | `-` | `[]` | `-` | `-` | No |\n" + + "| `input-with-description-only` | Input with description only | `-` | `-` | `-` | `-` | Yes |\n" + + "| `input-without-anything` | | `-` | `-` | `-` | `-` | Yes |\n" + + "| `number-with-default` | | `number` | `0` | `-` | `-` | No |\n" + + "| `number-without-default` | | `number` | `-` | `-` | `-` | Yes |\n" + + "| `string-with-default` | | `string` | `\"\"` | `-` | `-` | No |\n" + + "| `string-with-options` | | `string` | `-` | `[one two]` | `-` | Yes |\n" + + "| `string-with-regex` | | `string` | `-` | `-` | `^test.` | Yes |\n" + + "| `string-without-default` | | `string` | `-` | `-` | `-` | Yes |\n" + + filesystem := afero.NewMemMapFs() + componentDir := "templates" + componentPath := componentDir + "/first-component.yml" + outputFilePath := "README.md" + + err := filesystem.Mkdir(componentDir, 0o644) + require.NoError(t, err) + err = afero.WriteFile(filesystem, componentPath, []byte(componentContent), 0o644) + require.NoError(t, err) + + documentationGenerator := &RealDocumentationGenerator{} + documentationGenerator.GenerateDocumentation( + filesystem, + "templates", + "resources/default-template.md.gotmpl", + "github.com/test", + "1.0.0", + "README.md", + false, + ) + + outputExists, err := afero.Exists(filesystem, outputFilePath) + require.NoError(t, err) + assert.True(t, outputExists) + + outputContent, err := afero.ReadFile(filesystem, outputFilePath) + require.NoError(t, err) + assert.Contains(t, string(outputContent), expectedMarkdownTable) +} + +func TestGenerateDocumentationRendersMultipleJobsAndComponentsCorrectly(t *testing.T) { t.Parallel() firstComponentContent := `--- -# This is a description of the first component +# First Component spec: inputs: stage: - description: "The stage of the jobs" - type: "string" - default: "test" ... --- -# This is the first job of the first component +# First Component first job first-component-first-job: {} -# This is the second job of the first component +# First Component second job first-component-second-job: {} ` secondComponentContent := `--- -# This is a description of the second component +# Second Component spec: inputs: stage: - description: "The stage of the jobs" - type: "string" - default: "test" ... --- -# This is the first job of the second component +# Second Component first job second-component-first-job: {} -# This is the second job of the second component +# Second Component second job second-component-second-job: {} +... +` + + expectedMarkdown := `# Components Documentation + +## Components + +### first-component + +First Component +` + + "\n#### Usage of component `first-component`" + + "\n" + + "\nYou can add this component to an existing `.gitlab-ci.yml` file by using the `include:` keyword.\n" + + "\n" + + "```yaml\n" + + "include:\n" + + " - component: \"github.com/test/first-component@1.0.0\"\n" + + " inputs: {}\n" + + "```\n" + + ` +You can configure the component with the inputs documented below. +` + + "\n#### Inputs of component `first-component`\n" + + ` +| Name | Description | Type | Default | Options | Regex | Mandatory | +|------|-------------|------|---------|---------|-------|-----------| +` + + "| `stage` | | `-` | `-` | `-` | `-` | Yes |\n" + + "\n" + + "#### Jobs of component `first-component`\n" + + ` +The component will add the following jobs to your CI/CD Pipeline. +` + + "\n##### `first-component-first-job`\n" + + ` +First Component first job +` + + "\n##### `first-component-second-job`\n" + + ` +First Component second job + +### second-component + +Second Component +` + + "\n#### Usage of component `second-component`" + + "\n" + + "\nYou can add this component to an existing `.gitlab-ci.yml` file by using the `include:` keyword.\n" + + "\n" + + "```yaml\n" + + "include:\n" + + " - component: \"github.com/test/second-component@1.0.0\"\n" + + " inputs: {}\n" + + "```\n" + + ` +You can configure the component with the inputs documented below. +` + + "\n#### Inputs of component `second-component`\n" + + ` +| Name | Description | Type | Default | Options | Regex | Mandatory | +|------|-------------|------|---------|---------|-------|-----------| +` + + "| `stage` | | `-` | `-` | `-` | `-` | Yes |\n" + + "\n" + + "#### Jobs of component `second-component`\n" + + ` +The component will add the following jobs to your CI/CD Pipeline. +` + + "\n##### `second-component-first-job`\n" + + ` +Second Component first job +` + + "\n##### `second-component-second-job`\n" + + ` +Second Component second job ` filesystem := afero.NewMemMapFs() @@ -75,68 +235,35 @@ second-component-second-job: {} outputContent, err := afero.ReadFile(filesystem, outputFilePath) require.NoError(t, err) - assert.Contains(t, string(outputContent), "### first-component") - assert.Contains(t, string(outputContent), "### second-component") - assert.Contains(t, string(outputContent), "##### `second-component-second-job`") + assert.Equal(t, expectedMarkdown, string(outputContent)) } func TestGenerateDocumentationUsesCustomTemplate(t *testing.T) { t.Parallel() - firstComponentContent := `--- -# This is a description of the first component -spec: - inputs: - stage: - description: "The stage of the jobs" - type: "string" - default: "test" -... ---- -# This is the first job of the first component -first-component-first-job: {} - -# This is the second job of the first component -first-component-second-job: {} -` - - secondComponentContent := `--- -# This is a description of the second component + componentContent := `--- +# This is a custom template spec: inputs: stage: - description: "The stage of the jobs" - type: "string" - default: "test" ... ---- -# This is the first job of the second component -second-component-first-job: {} - -# This is the second job of the second component -second-component-second-job: {} ` customTemplateContent := ` - # Components Documentation - - {{ range $component := .Components }} - This is component {{ $component.Name }} - {{ end }} - ` +{{- range $component := .Components }} +Description: {{ $component.Description }} +{{- end }} +` filesystem := afero.NewMemMapFs() componentDir := "templates" - firstComponentPath := componentDir + "/first-component.yml" - secondComponentPath := componentDir + "/second-component.yml" + componentPath := componentDir + "/first-component.yml" outputFilePath := "README.md" customTemplateFilePath := "my-template.yml" err := filesystem.Mkdir(componentDir, 0o644) require.NoError(t, err) - err = afero.WriteFile(filesystem, firstComponentPath, []byte(firstComponentContent), 0o644) - require.NoError(t, err) - err = afero.WriteFile(filesystem, secondComponentPath, []byte(secondComponentContent), 0o644) + err = afero.WriteFile(filesystem, componentPath, []byte(componentContent), 0o644) require.NoError(t, err) err = afero.WriteFile(filesystem, customTemplateFilePath, []byte(customTemplateContent), 0o644) require.NoError(t, err) @@ -157,7 +284,7 @@ second-component-second-job: {} outputContent, err := afero.ReadFile(filesystem, outputFilePath) require.NoError(t, err) - assert.Contains(t, string(outputContent), "This is component first-component") + assert.Contains(t, string(outputContent), "Description: This is a custom template") } func TestBuildComponentDocumentationFromComponentsBuildsSortedComponentDocumentation(t *testing.T) { diff --git a/internal/gitlab/resources/default-template.md.gotmpl b/internal/gitlab/resources/default-template.md.gotmpl index 946c540..55a9b04 100644 --- a/internal/gitlab/resources/default-template.md.gotmpl +++ b/internal/gitlab/resources/default-template.md.gotmpl @@ -8,7 +8,7 @@ {{ $component.Description }} -#### Usage +#### Usage of component `{{ $component.Name }}` You can add this component to an existing `.gitlab-ci.yml` file by using the `include:` keyword. @@ -20,17 +20,45 @@ include: You can configure the component with the inputs documented below. -#### Inputs +#### Inputs of component `{{ $component.Name }}` -| Name | Description | Type | Default | -|------|-------------|------|---------| +| Name | Description | Type | Default | Options | Regex | Mandatory | +|------|-------------|------|---------|---------|-------|-----------| {{- range $input := $component.Inputs }} -| `{{ $input.Name }}` | {{ $input.Description }} | `{{ $input.Type }}` | `{{ $input.Default }}` | + {{- $mandatoryDisplay := "No" }} + {{- if eq $input.Default nil }} + {{- $mandatoryDisplay = "Yes" }} + {{- end }} + + {{- $defaultDisplay := $input.Default }} + {{- if eq $input.Default nil }} + {{- $defaultDisplay = "-" }} + {{- else if eq $input.Type "string" }} + {{- if eq $input.Default "" }} + {{- $defaultDisplay = "\"\"" }} + {{- end }} + {{- end }} + + {{- $optionsDisplay := $input.Options }} + {{- if eq $input.Options nil }} + {{- $optionsDisplay = "-" }} + {{- end }} + + {{- $regexDisplay := $input.Regex }} + {{- if eq $input.Regex "" }} + {{- $regexDisplay = "-" }} + {{- end }} + + {{- $typeDisplay := $input.Type}} + {{- if eq $input.Type "" }} + {{- $typeDisplay = "-" }} + {{- end }} +| `{{ $input.Name }}` | {{ $input.Description }} | `{{ $typeDisplay }}` | `{{ $defaultDisplay }}` | `{{ $optionsDisplay }}` | `{{ $regexDisplay }}` | {{ $mandatoryDisplay }} | {{- end }} -#### Jobs +#### Jobs of component `{{ $component.Name }}` -The component will add the following jobs to your CI/CD Pipeline +The component will add the following jobs to your CI/CD Pipeline. {{- range $job := $component.Jobs }} ##### `{{ $job.Name }}` diff --git a/templates/README.md b/templates/README.md index 2eae24d..59ef5e1 100644 --- a/templates/README.md +++ b/templates/README.md @@ -7,7 +7,7 @@ A GitLab CI/CD Component for generating Markdown documentation from GitLab CI/CD Components using `labdoc`. -#### Usage +#### Usage of component `labdoc-generate` You can add this component to an existing `.gitlab-ci.yml` file by using the `include:` keyword. @@ -19,21 +19,21 @@ include: You can configure the component with the inputs documented below. -#### Inputs +#### Inputs of component `labdoc-generate` -| Name | Description | Type | Default | -|------|-------------|------|---------| -| `additional-labdoc-parameters` | Additional parameters to add to the `labdoc generate` command. If you want this job to only check if your existing documentation is up-to-date, use the `--check` flag. | `string` | `` | -| `image` | The image to use for running `labdoc`. | `string` | `ernail/labdoc:1.0.0` | -| `labdoc-generate-job-extends` | The jobs that the job that generates the documentation should inherit from | `array` | `[]` | -| `labdoc-generate-job-name` | The name of the job that generates the documentation. | `string` | `labdoc-generate-job` | -| `output-file-path` | The path and name of the rendered file to be created. | `string` | `templates/README.md` | -| `repo-url` | The repository URL from which to include the GitLab CI/CD Component. Will be used in the documentation. | `string` | `` | -| `stage` | The stage of the jobs for generating the documentation. | `string` | `docs` | +| Name | Description | Type | Default | Options | Regex | Mandatory | +|------|-------------|------|---------|---------|-------|-----------| +| `additional-labdoc-parameters` | Additional parameters to add to the `labdoc generate` command. If you want this job to only check if your existing documentation is up-to-date, use the `--check` flag. | `string` | `""` | `-` | `-` | No | +| `image` | The image to use for running `labdoc`. | `string` | `ernail/labdoc:1.1.0` | `-` | `-` | No | +| `labdoc-generate-job-extends` | The jobs that the job that generates the documentation should inherit from. | `array` | `[]` | `-` | `-` | No | +| `labdoc-generate-job-name` | The name of the job that generates the documentation. | `string` | `labdoc-generate-job` | `-` | `-` | No | +| `output-file-path` | The path and name of the rendered file to be created. | `string` | `templates/README.md` | `-` | `-` | No | +| `repo-url` | The repository URL from which to include the GitLab CI/CD Component. Will be used in the documentation. | `string` | `-` | `-` | `-` | Yes | +| `stage` | The stage of the jobs for generating the documentation. | `string` | `docs` | `-` | `-` | No | -#### Jobs +#### Jobs of component `labdoc-generate` -The component will add the following jobs to your CI/CD Pipeline +The component will add the following jobs to your CI/CD Pipeline. ##### `$[[ inputs.labdoc-generate-job-name ]]` diff --git a/templates/labdoc-generate.yml b/templates/labdoc-generate.yml index 04ce775..4f2d2bf 100644 --- a/templates/labdoc-generate.yml +++ b/templates/labdoc-generate.yml @@ -8,7 +8,7 @@ spec: type: "string" default: "labdoc-generate-job" labdoc-generate-job-extends: - description: "The jobs that the job that generates the documentation should inherit from" + description: "The jobs that the job that generates the documentation should inherit from." type: "array" default: [] stage: @@ -18,7 +18,7 @@ spec: image: description: "The image to use for running `labdoc`." type: "string" - default: "ernail/labdoc:1.0.0" + default: "ernail/labdoc:1.1.0" repo-url: description: >- The repository URL from which to include the GitLab CI/CD Component.