Skip to content
Closed
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: 5 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ concurrency:
jobs:
validate-contributors:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
go-version: ["1.23.x"]
env:
runnerUsername: ${{ github.actor }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Test branch output
run: git branch --show-current
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23.2"
- name: Validate
run: go run ./scripts/validate-contributor-readmes/main.go
run: go build ./scripts/validate-contributors && ./validate-contributors
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,9 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

## Script artifacts
/validate-contributors
/validate-modules
/validate-templates
/validate-repo-structure
13 changes: 13 additions & 0 deletions cmd/github/github.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Package github contains utilities for making it easier to access GitHub
// resources via its official API
package github

func ActionsRunnerUsername() (string, error) {
return "Parkreiner", nil
}

func FetchCoderEmployeeUsernames() (map[string]struct{}, error) {
m := map[string]struct{}{}
m["Parkreiner"] = struct{}{}
return m, nil
}
125 changes: 125 additions & 0 deletions cmd/readme/readme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Package readme contains general-use utilities for processing README files.
package readme

import (
"bufio"
"errors"
"fmt"
"strings"
)

// RootRegistryPath is the directory where all READMEs that need to be validated
// should live.
const RootRegistryPath = "./registry"

// Readme represents a single README file within the repo (usually within the
// /registry directory).
type Readme struct {
FilePath string
RawText string
}

// SeparateFrontmatter attempts to separate a README file's frontmatter content
// from the main README body, returning both values in that order. It does not
// validate whether the structure of the frontmatter is valid (i.e., that it's
// structured as YAML).
func SeparateFrontmatter(readmeText string) (string, string, error) {
if readmeText == "" {
return "", "", errors.New("README is empty")
}

const fence = "---"
fm := ""
body := ""
fenceCount := 0
lineScanner := bufio.NewScanner(
strings.NewReader(strings.TrimSpace(readmeText)),
)
for lineScanner.Scan() {
nextLine := lineScanner.Text()
if fenceCount < 2 && nextLine == fence {
fenceCount++
continue
}
// Break early if the very first line wasn't a fence, because then we
// know for certain that the README has problems
if fenceCount == 0 {
break
}

// It should be safe to trim each line of the frontmatter on a per-line
// basis, because there shouldn't be any extra meaning attached to the
// indentation. The same does NOT apply to the README; best we can do is
// gather all the lines, and then trim around it
if inReadmeBody := fenceCount >= 2; inReadmeBody {
body += nextLine + "\n"
} else {
fm += strings.TrimSpace(nextLine) + "\n"
}
}
if fenceCount < 2 {
return "", "", errors.New("README does not have two sets of frontmatter fences")
}
if fm == "" {
return "", "", errors.New("readme has frontmatter fences but no frontmatter content")
}

return fm, strings.TrimSpace(body), nil
}

// ValidationPhase represents a specific phase during README validation. It is
// expected that each phase is discrete, and errors during one will prevent a
// future phase from starting.
type ValidationPhase int

const (
// ValidationPhaseFilesystemRead indicates when a README file is being read
// from the file system
ValidationPhaseFilesystemRead ValidationPhase = iota
// ValidationPhaseReadmeParsing indicates when a README's frontmatter is being
// parsed as YAML. This phase does not include YAML validation.
ValidationPhaseReadmeParsing
// ValidationPhaseReadmeValidation indicates when a README's frontmatter is
// being validated as proper YAML with expected keys.
ValidationPhaseReadmeValidation
// ValidationPhaseAssetCrossReference indicates when a README's frontmatter
// is having all its relative URLs be validated for whether they point to
// valid resources.
ValidationPhaseAssetCrossReference
)

func (p ValidationPhase) String() string {
switch p {
case ValidationPhaseFilesystemRead:
return "Filesystem reading"
case ValidationPhaseReadmeParsing:
return "README parsing"
case ValidationPhaseReadmeValidation:
return "README validation"
case ValidationPhaseAssetCrossReference:
return "Cross-referencing asset references"
default:
return "Unknown validation phase"
}
}

var _ error = ValidationPhaseError{}

// ValidationPhaseError represents an error that occurred during a specific
// phase of README validation. It should be used to collect ALL validation
// errors that happened during a specific phase, rather than the first one
// encountered.
type ValidationPhaseError struct {
Phase ValidationPhase
Errors []error
}

func (vpe ValidationPhaseError) Error() string {
msg := fmt.Sprintf("Error during %q phase of README validation:", vpe.Phase.String())
for _, e := range vpe.Errors {
msg += fmt.Sprintf("\n- %v", e)
}
msg += "\n"

return msg
}
7 changes: 7 additions & 0 deletions registry/TheZoker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
display_name: The Zoker
bio: I'm a master computer science student at the TU munich and a webdesigner.
github: TheZoker
website: https://gareis.io/
status: community
---
60 changes: 60 additions & 0 deletions registry/TheZoker/modules/nodejs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
display_name: Node.js
description: Install Node.js via nvm
icon: ../.icons/node.svg
verified: false
tags: [helper]
---

# nodejs

Automatically installs [Node.js](https://github.com/nodejs/node) via [nvm](https://github.com/nvm-sh/nvm). It can also install multiple versions of node and set a default version. If no options are specified, the latest version is installed.

```tf
module "nodejs" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/nodejs/coder"
version = "1.0.10"
agent_id = coder_agent.example.id
}
```

## Install multiple versions

This installs multiple versions of Node.js:

```tf
module "nodejs" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/nodejs/coder"
version = "1.0.10"
agent_id = coder_agent.example.id
node_versions = [
"18",
"20",
"node"
]
default_node_version = "20"
}
```

## Full example

A example with all available options:

```tf
module "nodejs" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/nodejs/coder"
version = "1.0.10"
agent_id = coder_agent.example.id
nvm_version = "v0.39.7"
nvm_install_prefix = "/opt/nvm"
node_versions = [
"16",
"18",
"node"
]
default_node_version = "16"
}
```
8 changes: 8 additions & 0 deletions registry/WhizUs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
display_name: WhizUs
bio: WhizUs is your premier choice for DevOps, Kubernetes, and Cloud Native consulting. Based in Vienna we combine our expert solutions with a strong commitment to the community. Explore automation, scalability and drive success through collaboration.
github: WhizUs
linkedin: https://www.linkedin.com/company/whizus
website: https://gareis.io/
status: community
---
116 changes: 116 additions & 0 deletions registry/WhizUs/modules/exoscale-instance-type/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
display_name: Exoscale Instance Type
description: A parameter with human readable exoscale instance names
icon: ../.icons/exoscale.svg
verified: false
tags: [helper, parameter, instances, exoscale]
---

# exoscale-instance-type

A parameter with all Exoscale instance types. This allows developers to select
their desired virtual machine for the workspace.

Customize the preselected parameter value:

```tf
module "exoscale-instance-type" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-instance-type/coder"
version = "1.0.12"
default = "standard.medium"
}

resource "exoscale_compute_instance" "instance" {
type = module.exoscale-instance-type.value
# ...
}

resource "coder_metadata" "workspace_info" {
item {
key = "instance type"
value = module.exoscale-instance-type.name
}
}
```

![Exoscale instance types](../.images/exoscale-instance-types.png)

## Examples

### Customize type

Change the display name a type using the corresponding maps:

```tf
module "exoscale-instance-type" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-instance-type/coder"
version = "1.0.12"
default = "standard.medium"

custom_names = {
"standard.medium" : "Mittlere Instanz" # German translation
}

custom_descriptions = {
"standard.medium" : "4 GB Arbeitsspeicher, 2 Kerne, 10 - 400 GB Festplatte" # German translation
}
}

resource "exoscale_compute_instance" "instance" {
type = module.exoscale-instance-type.value
# ...
}

resource "coder_metadata" "workspace_info" {
item {
key = "instance type"
value = module.exoscale-instance-type.name
}
}
```

![Exoscale instance types Custom](../.images/exoscale-instance-custom.png)

### Use category and exclude type

Show only gpu1 types

```tf
module "exoscale-instance-type" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/exoscale-instance-type/coder"
version = "1.0.12"
default = "gpu.large"
type_category = ["gpu"]
exclude = [
"gpu2.small",
"gpu2.medium",
"gpu2.large",
"gpu2.huge",
"gpu3.small",
"gpu3.medium",
"gpu3.large",
"gpu3.huge"
]
}

resource "exoscale_compute_instance" "instance" {
type = module.exoscale-instance-type.value
# ...
}

resource "coder_metadata" "workspace_info" {
item {
key = "instance type"
value = module.exoscale-instance-type.name
}
}
```

![Exoscale instance types category and exclude](../.images/exoscale-instance-exclude.png)

## Related templates

A related exoscale template will be provided soon.
Loading