Skip to content

Commit

Permalink
Merge pull request #79 from opentofu/issue_workflow
Browse files Browse the repository at this point in the history
Provider/Module submission workflow
  • Loading branch information
cam72cam authored Dec 7, 2023
2 parents a26d229 + 592e39a commit 74bfbcf
Show file tree
Hide file tree
Showing 7 changed files with 431 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/module.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Submit new Module
description: Submit a new OpenTofu Module
title: "Module: "
labels: ["module", "submission"]
body:
- type: input
id: module_repository
attributes:
label: Module Repository
description: Path to a public GitHub repository following the pattern {owner}/terraform-{target}-{name}, ex. GoogleCloudPlatform/terraform-google-secured-data-warehouse
validations:
required: true
- type: checkboxes
id: dco
attributes:
label: DCO
options:
- label: I sign this project's [DCO](https://developercertificate.org/)
required: true
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/provider.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Submit new Provider
description: Submit a new OpenTofu Provider
title: "Provider: "
labels: ["provider", "submission"]
body:
- type: input
id: repository
attributes:
label: Provider Repository
description: Path to a public GitHub repository following the pattern {owner}/terraform-provider-{name}, ex. opentofu/terraform-provider-aws
validations:
required: true
- type: checkboxes
id: dco
attributes:
label: DCO
options:
- label: I sign this project's [DCO](https://developercertificate.org/)
required: true
152 changes: 152 additions & 0 deletions .github/workflows/issue-to-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
name: Issue Submission to Pull Request
on:
issues:
types:
[opened, edited]

jobs:
submit-provider:
if: contains(github.event.issue.labels.*.name, 'provider') && contains(github.event.issue.labels.*.name, 'submission')
runs-on: ubuntu-latest
permissions:
issues: write
contents: write
pull-requests: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version-file: './src/go.mod'

- name: Validate Provider and Create PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
NUMBER: ${{ github.event.issue.number }}
URL: ${{ github.event.issue.url }}
TITLE: ${{ github.event.issue.title }}
BODY: ${{ github.event.issue.body }}
working-directory: ./src
run: |
set +e
echo "$BODY" | grep "\- \[[xX]\] I sign this project's \[DCO\](https://developercertificate.org/)"
if [[ "$?" != 0 ]]; then
gh issue comment $NUMBER -b "DCO must be signed to submit this repository"
exit 1
fi
set -e
repository=$(echo "$BODY" | grep "### Provider Repository" -A2 | tail -n1 | sed -e 's/[\r\n]//g')
set +e
go run ./cmd/add-provider -repository="$repository" -output=./output.json
if [[ "$?" != 0 ]]; then
gh issue comment $NUMBER -b "$(cat ./output.json | jq -r '.validation')"
exit 1
fi
set -e
namespace=$(cat ./output.json | jq -r '.namespace')
name=$(cat ./output.json | jq -r '.name')
jsonfile=$(cat ./output.json | jq -r '.file')
# Create Branch
branch=provider-submission_${namespace}_${name}
set +e
git checkout -b $branch
if [[ "$?" != 0 ]]; then
gh issue comment $NUMBER -b "Failed validation: A branch already exists for this provider '$branch'"
exit 1
fi
set -e
# Add result
git add $jsonfile
# Commit and push result
git config --global user.email "no-reply@opentofu.org"
git config --global user.name "OpenTofu Automation"
git commit -s -m "Create provider $namespace/$name"
git push -u origin $branch
# Create pull request and update issue
pr=$(gh pr create --title "$TITLE" --body "Created $(echo $jsonfile | sed -e 's/../src/') for provider $namespace/$name. See issue #$NUMBER for details.") #--assignee opentofu/core-engineers)
gh issue comment $NUMBER -b "Your submission has been validated and has moved on to the pull request phase ($pr). This issue has been locked."
gh issue lock $NUMBER -r resolved
submit-module:
if: contains(github.event.issue.labels.*.name, 'module') && contains(github.event.issue.labels.*.name, 'submission')
runs-on: ubuntu-latest
permissions:
issues: write
contents: write
pull-requests: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version-file: './src/go.mod'

- name: Validate Module and Create PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
NUMBER: ${{ github.event.issue.number }}
URL: ${{ github.event.issue.url }}
TITLE: ${{ github.event.issue.title }}
BODY: ${{ github.event.issue.body }}
working-directory: ./src
run: |
set +e
echo "$BODY" | grep "\- \[[xX]\] I sign this project's \[DCO\](https://developercertificate.org/)"
if [[ "$?" != 0 ]]; then
gh issue comment $NUMBER -b "DCO must be signed to submit this repository"
exit 1
fi
set -e
repository=$(echo "$BODY" | grep "### Module Repository" -A2 | tail -n1 | sed -e 's/[\r\n]//g')
set +e
go run ./cmd/add-module -repository="$repository" -output=./output.json
if [[ "$?" != 0 ]]; then
gh issue comment $NUMBER -b "$(cat ./output.json | jq -r '.validation')"
exit 1
fi
set -e
namespace=$(cat ./output.json | jq -r '.namespace')
name=$(cat ./output.json | jq -r '.name')
target=$(cat ./output.json | jq -r '.target')
jsonfile=$(cat ./output.json | jq -r '.file')
# Create Branch
branch=module-submission_${namespace}_${name}_${target}
set +e
git checkout -b $branch
if [[ "$?" != 0 ]]; then
gh issue comment $NUMBER -b "Failed validation: A branch already exists for this module '$branch'"
exit 1
fi
set -e
# Add result
git add $jsonfile
# Commit and push result
git config --global user.email "no-reply@opentofu.org"
git config --global user.name "OpenTofu Automation"
git commit -s -m "Create module $namespace/$name/$target"
git push -u origin $branch
# Create pull request and update issue
pr=$(gh pr create --title "$TITLE" --body "Created $(echo $jsonfile | sed -e 's/../src/') for module $namespace/$name/$target. See issue #$NUMBER for details.") #--assignee opentofu/core-engineers)
gh issue comment $NUMBER -b "Your submission has been validated and has moved on to the pull request phase ($pr). This issue has been locked."
gh issue lock $NUMBER -r resolved
118 changes: 118 additions & 0 deletions src/cmd/add-module/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"context"
"flag"
"fmt"
"log/slog"
"os"
"regexp"
"strings"

"github.com/opentofu/registry-stable/internal/files"
"github.com/opentofu/registry-stable/internal/github"
"github.com/opentofu/registry-stable/internal/module"

regaddr "github.com/opentofu/registry-address"
)

type Output struct {
File string `json:"file"`
Namespace string `json:"namespace"`
Name string `json:"name"`
Target string `json:"target"`
Validation string `json:"validation"`
}

func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

repository := flag.String("repository", "", "The module repository to add")
outputFile := flag.String("output", "", "Path to write JSON result to")
moduleDataDir := flag.String("module-data", "../modules", "Directory containing the module data")

flag.Parse()

ctx := context.Background()
token, err := github.EnvAuthToken()
if err != nil {
logger.Error("Initialization Error", slog.Any("err", err))
os.Exit(1)
}
ghClient := github.NewClient(ctx, logger, token)

output := Output{}

err = func() error {
// Lower case input
re := regexp.MustCompile("(?P<Namespace>[a-zA-Z0-9]+)/terraform-(?P<Target>[a-zA-Z0-9]*)-(?P<Name>[a-zA-Z0-9-]*)")
match := re.FindStringSubmatch(*repository)
if match == nil {
return fmt.Errorf("Invalid repository name: %s", *repository)
}

submitted := module.Module{
Namespace: match[re.SubexpIndex("Namespace")],
Name: match[re.SubexpIndex("Name")],
TargetSystem: match[re.SubexpIndex("Target")],
Directory: *moduleDataDir,
Logger: logger,
Github: ghClient,
}

_, err = regaddr.ParseModuleSource(fmt.Sprintf("%s/%s/%s", submitted.Namespace, submitted.Name, submitted.TargetSystem))
if err != nil {
return err
}

modules, err := module.ListModules(*moduleDataDir, "", logger, ghClient)
if err != nil {
return err
}
for _, p := range modules {
if strings.ToLower(p.RepositoryURL()) == strings.ToLower(submitted.RepositoryURL()) {
return fmt.Errorf("Repository already exists in the registry, %s", p.RepositoryURL())
}
}

err = submitted.WriteMetadata(module.Metadata{})
if err != nil {
return fmt.Errorf("An unexpected error occured: %w", err)
}

err = submitted.UpdateMetadataFile()
if err != nil {
return fmt.Errorf("An unexpected error occured: %w", err)
}

meta, err := submitted.ReadMetadata()
if err != nil {
return fmt.Errorf("An unexpected error occured: %w", err)
}
if len(meta.Versions) == 0 {
return fmt.Errorf("No versions detected for repository %s", submitted.RepositoryURL())
}

output.Namespace = submitted.Namespace
output.Name = submitted.Name
output.Target = submitted.TargetSystem
output.File = submitted.MetadataPath()
return nil
}()

if err != nil {
logger.Error("Unable to add module", slog.Any("err", err))
output.Validation = err.Error()
// Don't exit yet, still need to write the json.
}

jsonErr := files.SafeWriteObjectToJSONFile(*outputFile, output)
if jsonErr != nil {
// This really should not happen
panic(jsonErr)
}

if err != nil {
os.Exit(1)
}
}
Loading

0 comments on commit 74bfbcf

Please sign in to comment.