Goit

Simple and lightweight Git web server
git clone https://git.omkov.net/Goit
git clone git@git.omkov.net:Goit
Log | Tree | Refs | README | Download

Goit/src/repo/tag.go (119 lines, 2.9 KiB) -rw-r--r-- blame download

0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
// Copyright (C) 2025, Jakob Wakeling
// All rights reserved.

package repo

import (
	"errors"
	"net/http"
	"path/filepath"
	"time"

	"github.com/Jamozed/Goit/src/goit"
	"github.com/Jamozed/Goit/src/util"
	"github.com/go-chi/chi/v5"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/object"
)

func HandleTag(w http.ResponseWriter, r *http.Request) {
	auth, user, err := goit.Auth(w, r, true)
	if err != nil {
		util.PrintError(err)
		goit.HttpError(w, http.StatusInternalServerError)
		return
	}

	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
	if err != nil {
		goit.HttpError(w, http.StatusInternalServerError)
		return
	} else if repo == nil || !goit.IsVisible(repo, auth, user) {
		goit.HttpError(w, http.StatusNotFound)
		return
	}

	data := struct {
		HeaderFields
		Title                     string
		Tag, Author, Date, Commit string
		Parents                   []string
		Message                   string
	}{
		HeaderFields: GetHeaderFields(auth, user, repo, r.Host),
		Title:        repo.Name + " - Tags",
	}

	gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true))
	if err != nil {
		util.PrintError(err)
		goit.HttpError(w, http.StatusInternalServerError)
		return
	}

	head, err := gr.Head()
	if err != nil {
		if !errors.Is(err, plumbing.ErrReferenceNotFound) {
			util.PrintError(err)
			goit.HttpError(w, http.StatusInternalServerError)
			return
		}
	} else {
		if readme, _ := findPattern(gr, head, readmePattern); readme != "" {
			data.Readme = filepath.Join("/", repo.Name, "file", readme)
		}
		if licence, _ := findPattern(gr, head, licencePattern); licence != "" {
			data.Licence = filepath.Join("/", repo.Name, "file", licence)
		}
	}

	ref, err := gr.Tag(chi.URLParam(r, "tag"))
	if errors.Is(err, plumbing.ErrReferenceNotFound) {
		goit.HttpError(w, http.StatusNotFound)
		return
	} else if err != nil {
		util.PrintError(err)
		goit.HttpError(w, http.StatusInternalServerError)
		return
	}

	data.Tag = ref.Name().Short()

	var commit *object.Commit
	if tag, err := gr.TagObject(ref.Hash()); err != nil {
		if !errors.Is(err, plumbing.ErrObjectNotFound) {
			util.PrintError(err)
			goit.HttpError(w, http.StatusInternalServerError)
			return
		}

		/* Tag is not annotated. */
		if commit, err = gr.CommitObject(ref.Hash()); err != nil {
			util.PrintError(err)
			goit.HttpError(w, http.StatusInternalServerError)
			return
		}

		data.Author = commit.Author.String()
		data.Message = commit.Message
	} else {
		/* Tag is annotated. */
		if commit, err = gr.CommitObject(tag.Target); err != nil {
			util.PrintError(err)
			goit.HttpError(w, http.StatusInternalServerError)
			return
		}

		data.Author = tag.Tagger.String()
		data.Message = tag.Message
	}

	data.Date = commit.Author.When.UTC().Format(time.DateTime)
	data.Commit = commit.Hash.String()

	if err := goit.Tmpl.ExecuteTemplate(w, "repo/tag", data); err != nil {
		util.PrintError(err)
	}
}