Skip to content

Custom tag formatting #189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jaitaiwan opened this issue Feb 21, 2025 · 4 comments · May be fixed by #190
Open

Custom tag formatting #189

jaitaiwan opened this issue Feb 21, 2025 · 4 comments · May be fixed by #190

Comments

@jaitaiwan
Copy link

jaitaiwan commented Feb 21, 2025

I'm attempting to cause go-semantic-releases to call a target a custom plugin I've written so that I can get it to check for a next release based off a custom suffix. E.g. specify a tag format of "{{.Folder}}-v{{.Version}}". This makes easyish support for monorepo stuff.

Do you have instructions or an example anywhere of how to get semantic-release to know about a particular plugin?

@jaitaiwan
Copy link
Author

jaitaiwan commented Feb 21, 2025

Since I wrote this I found:

However its still not entirely clear, how one might hook in and allow a custom tag format, especially when determining the semver. If you can give me some pointers that would be helpful; I should have created this as a discussion sorry.

@jaitaiwan
Copy link
Author

I've done more research and investigation into tag support. First of all I think tag formatting would be a fairly easy way to get 99% of the way towards monorepo support (cc: #77).

Afaict we can have a --tag-format option added to the CLI which gets passed as a provider option to the providers. Tag Format would be a go text/template where {{.Version}} is the semver with or without the v prefix. The resulting parsed template would need to be a valid regex.

E.g. a parsed version of the tag format might look like myproject-(v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)

Where {{.Version}} has been replaced by the semver regex

To make it easy to specify dynamic tag formatting we could add env var injection into the template system:

tmpl, err := template.New("tagFormat").Funcs(template.FuncMap{
		"env": func(key string) string {
			if strings.HasPrefix("SEMREL_") {
			  return os.Getenv(key)
			}

			return ""
		},
	}).Parse(format)

So that one could do something like SEMREL_PROJECT=myproject in the github action environment variables and provide a tag format of {{.Env.SEMREL_PROJECT}}-{{.Version}} so that a tag like myproject-v1.0.0 could be generated.

Then the option would be to either try and keep this tag format logic entirely inside the providers, or have some of it in the providers (like when looking at tags) but then make the semrel package aware of this format too. If you don't make semrel aware you just have to note that the CreateRelease function would be the only place that would be used.

Here's an example github action that would use this:

name: Binary Semantic Releases

on:
  push:
    branches:
      - trunk  # Runs only on the main (trunk) branch

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Required for go-semantic-release

      - name: Generate token
        id: generate_token
        uses: actions/create-github-app-token@v1
        with:
          app-id: ${{ secrets.GH_APP_ID }}
          private-key: ${{ secrets.GH_PRIV_PEM }}

      - name: Install go-semantic-release
        run: |
          go install github.com/go-semantic-release/semantic-release/v2/cmd/semantic-release@latest

      - name: Detect Changed Folders
        id: changed_dirs
        run: |
          # Get modified files
          MODIFIED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }})

          # Detect if internal/, pkg/, or the test workflow changed
          if echo "$MODIFIED_FILES" | grep -Eq '^internal/|^pkg/|^.github/workflows/mypipeline.yml|^.releaserc$'; then
            echo "Changes detected in internal/, pkg/, or workflow. Triggering release for all binaries..."
            FOLDERS=$(ls cmd | jq -R -s -c 'split("\n")[:-1]')
          else
            # Detect which cmd/* directories changed
            FOLDERS=$(echo "$MODIFIED_FILES" | grep '^cmd/' | cut -d '/' -f2 | sort -u | jq -R -s -c 'split("\n")[:-1]')
          fi

          echo "folders=$FOLDERS" >> $GITHUB_ENV

      - name: Run go-semantic-release per Folder
        if: env.folders != '[]'
        run: |
          export GITHUB_TOKEN="${{ steps.generate_token.outputs.token }}"
          
          for folder in $(echo $folders | jq -r '.[]'); do
            echo "Releasing for cmd/$folder"

            # Run semantic release with the tag formatter plugin
            $HOME/go/bin/semantic-release --tag-format="$folder-{{.Version}}"
          done

If these changes seem feasible and maintainers (CC @christophwitzko ) are interested and willing to give pointers then I'd be happy to go ahead and make this happen.

jaitaiwan pushed a commit to TheOpenTrustee/semantic-release that referenced this issue Feb 26, 2025
@jaitaiwan
Copy link
Author

I've attached some draft PRs to see if it's what maintainers would be keen to support

@jaitaiwan
Copy link
Author

I've done testing and I believe that it works with the current implementations now. TagFormat will be ignored for non github providers but that should be okay for now.

The next thing I think that needs to happen for monorepos is that we have the ability to not perform a release but still tag. I think the best way to have this happen would be to have the success hook run at the end of a dry run still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant