Compare commits

..

11 Commits
v1 ... main

Author SHA1 Message Date
Mandresy RABENJAHARISON
dbdab7caaa Merge branch 'release/v1.0.1' 2025-09-29 17:32:29 +03:00
Mandresy RABENJAHARISON
b02b68c668 fix: update branch creation action to use 'develop' instead of 'main' 2025-09-29 17:31:09 +03:00
Mandresy RABENJAHARISON
e202c32a31 fix: update branch creation workflow to use specific action URL 2025-09-29 17:27:04 +03:00
Mandresy RABENJAHARISON
c43a4473ee fix: specify 'main' as default ref and enable clean checkout in branch creation workflow 2025-09-29 17:21:18 +03:00
Mandresy RABENJAHARISON
1b936d8431 feat: log prefix and enhance handling for branch creation 2025-09-29 17:07:55 +03:00
Mandresy RABENJAHARISON
c4cf4aa33e feat: support branch creation from 'main' for hotfixes and handle reopened issues in workflow 2025-09-29 17:01:50 +03:00
Mandresy RABENJAHARISON
bdfc0beb23 feat: add workflow to create and link branch for new issues 2025-09-29 16:44:43 +03:00
Mandresy RABENJAHARISON
73da559bf3 chore: optimize Dockerfile layers and remove unused reflect import 2025-09-29 15:41:33 +03:00
Mandresy RABENJAHARISON
7c0d7d26e4 fix: correct ISSUE_LABELS parsing and logging 2025-09-29 15:30:08 +03:00
Mandresy RABENJAHARISON
06f6737f96 chore: show type of labelsEnvg 2025-09-29 15:02:24 +03:00
Mandresy RABENJAHARISON
444487b324 feat: enhance label parsing to support multiple formats and improve logging 2025-09-16 16:27:45 +03:00
4 changed files with 102 additions and 21 deletions

View File

@ -0,0 +1,20 @@
name: Create a new branch and link it back to the issue.
on:
issues:
types:
- opened
- reopened
jobs:
create-branch:
runs-on: node1-runner-timesheet1
steps:
- name: Checkout Repository
uses: actions/checkout@v3
clean: 'true'
ref: 'main'
- name: Create a New Branch and Link to Issue
uses: https://gitea.ethumada.com/gitea/new-issue-branch@develop

View File

@ -8,15 +8,11 @@ RUN apk add --no-cache git ca-certificates
WORKDIR /src WORKDIR /src
# Copy *both* dependency files first so Docker-layer caching works # Bring in the source (vendor dir included)
COPY go.mod go.sum ./
RUN go mod download
# Bring in the rest of the source
COPY . . COPY . .
# Build static binary # Build static binary using vendored dependencies
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/action ./main.go RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod=vendor -o /out/action ./main.go
######################## ########################
# — Runtime stage — # — Runtime stage —

View File

@ -9,7 +9,7 @@ runs:
using: "docker" using: "docker"
image: "Dockerfile" image: "Dockerfile"
env: env:
ISSUE_LABELS: ${{ gitea.event.issue.labels }} ISSUE_LABELS: ${{ join(gitea.event.issue.labels.*.name, ',') }}
ISSUE_NUMBER: ${{ gitea.event.issue.number }} ISSUE_NUMBER: ${{ gitea.event.issue.number }}
ODOO_TICKET_NUMBER: ${{ gitea.event.issue.ref }} ODOO_TICKET_NUMBER: ${{ gitea.event.issue.ref }}
ISSUE_TITLE: ${{ gitea.event.issue.title }} ISSUE_TITLE: ${{ gitea.event.issue.title }}

91
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -28,7 +29,10 @@ func main() {
logger.Printf("ODOO_TICKET_NUMBER: %s\n", issueOdooTicketString) logger.Printf("ODOO_TICKET_NUMBER: %s\n", issueOdooTicketString)
issueTitle := os.Getenv("ISSUE_TITLE") issueTitle := os.Getenv("ISSUE_TITLE")
labelsStr := os.Getenv("ISSUE_LABELS")
labelsEnv := os.Getenv("ISSUE_LABELS")
logger.Printf("ISSUE_LABELS: %s\n", labelsEnv)
issueNumberString := os.Getenv("ISSUE_NUMBER") issueNumberString := os.Getenv("ISSUE_NUMBER")
giteaToken := os.Getenv("GITEA_TOKEN") giteaToken := os.Getenv("GITEA_TOKEN")
@ -57,14 +61,17 @@ func main() {
logger.Printf("Odoo ticket ID: %d\n", issueOdooTicketID) logger.Printf("Odoo ticket ID: %d\n", issueOdooTicketID)
// Map labels to Git Flow prefixes // Map labels to Git Flow prefixes
prefix := "feature" labels := parseLabels(labelsEnv, logger)
if labelsStr != "" { if len(labels) > 0 {
prefix, err = getPrefixFromLabels(labelsStr) logger.Printf("Extracted labels: %s\n", strings.Join(labels, ", "))
} }
prefix := "feature"
prefix, err = getPrefixFromLabels(labels)
if err != nil { if err != nil {
logger.Printf("Error while determining the prefix: %v\n", err) logger.Printf("Error while determining the prefix: %v\n", err)
os.Exit(1) os.Exit(1)
} }
logger.Printf("Chosen prefix: %s\n", prefix)
// Form the branch name in the format "prefix/ticket-number" // Form the branch name in the format "prefix/ticket-number"
branchName := fmt.Sprintf("%s/ticket-%d", prefix, issueOdooTicketID) branchName := fmt.Sprintf("%s/ticket-%d", prefix, issueOdooTicketID)
@ -108,8 +115,17 @@ func main() {
logger.Printf("Branch '%s' already exists. No action taken.\n", branchName) logger.Printf("Branch '%s' already exists. No action taken.\n", branchName)
} else { } else {
// Create and push the branch // Create and push the branch
logger.Printf("Creating branch '%s' from 'develop'.\n", branchName) originBranch := "origin/develop"
err = runCommand(logger, "git", "checkout", "-b", branchName, "origin/develop")
logger.Printf("Prefix is : %s", prefix)
if prefix == "hotfix" {
originBranch = "origin/main"
} else {
logger.Printf("hotfix != %s", prefix)
}
logger.Printf("Creating branch '%s' from '%s'.\n", branchName, originBranch)
err = runCommand(logger, "git", "checkout", "-b", branchName, originBranch)
if err != nil { if err != nil {
logger.Printf("Error while creating the branch: %v\n", err) logger.Printf("Error while creating the branch: %v\n", err)
os.Exit(1) os.Exit(1)
@ -150,7 +166,7 @@ func main() {
} }
// Function to map labels to prefixes // Function to map labels to prefixes
func getPrefixFromLabels(labelsStr string) (string, error) { func getPrefixFromLabels(labels []string) (string, error) {
// Define the label âž” prefix correspondence // Define the label âž” prefix correspondence
labelPrefixMap := map[string]string{ labelPrefixMap := map[string]string{
"enhancement": "feature", "enhancement": "feature",
@ -158,9 +174,6 @@ func getPrefixFromLabels(labelsStr string) (string, error) {
"bug": "hotfix", "bug": "hotfix",
} }
// Split labels (assuming they are comma-separated)
labels := strings.Split(labelsStr, ",")
// Create a mapping with lower-case keys // Create a mapping with lower-case keys
labelPrefixMapLower := make(map[string]string) labelPrefixMapLower := make(map[string]string)
for key, value := range labelPrefixMap { for key, value := range labelPrefixMap {
@ -169,9 +182,9 @@ func getPrefixFromLabels(labelsStr string) (string, error) {
} }
for _, label := range labels { for _, label := range labels {
label = strings.TrimSpace(label) trimmed := strings.TrimSpace(label)
labelLower := strings.ToLower(label) labelLower := strings.ToLower(trimmed)
fmt.Printf("Current label: %s", labelLower) fmt.Printf("Current label: %s\n", labelLower)
if prefix, exists := labelPrefixMapLower[labelLower]; exists { if prefix, exists := labelPrefixMapLower[labelLower]; exists {
return prefix, nil return prefix, nil
} }
@ -180,6 +193,58 @@ func getPrefixFromLabels(labelsStr string) (string, error) {
return "feature", nil return "feature", nil
} }
// Parse ISSUE_LABELS env which can be:
// - JSON array of strings: ["bug", "enhancement"]
// - JSON array of objects: [{"name":"bug"},{"name":"ui"}]
// - Comma-separated string: "bug, enhancement"
func parseLabels(raw string, logger *log.Logger) []string {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
// Try JSON array of strings
var arrStr []string
if err := json.Unmarshal([]byte(raw), &arrStr); err == nil {
return arrStr
}
// Try JSON array of objects with name
type lbl struct {
Name string `json:"name"`
}
var arrObj []lbl
if err := json.Unmarshal([]byte(raw), &arrObj); err == nil {
out := make([]string, 0, len(arrObj))
for _, o := range arrObj {
if o.Name != "" {
out = append(out, o.Name)
}
}
if len(out) > 0 {
return out
}
}
// Fallback: comma-separated values
if strings.Contains(raw, ",") {
parts := strings.Split(raw, ",")
for i := range parts {
parts[i] = strings.TrimSpace(parts[i])
}
return parts
}
// Last resort: if it looks like JSON but couldn't parse, log and return nil
if strings.HasPrefix(raw, "[") || strings.HasPrefix(raw, "{") {
logger.Printf("Warning: could not parse ISSUE_LABELS JSON: %s\n", raw)
return nil
}
// Otherwise single token
return []string{raw}
}
func runCommand(logger *log.Logger, name string, arg ...string) error { func runCommand(logger *log.Logger, name string, arg ...string) error {
cmd := exec.Command(name, arg...) cmd := exec.Command(name, arg...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout