Compare commits

..

20 Commits

Author SHA1 Message Date
2a9707ec89 chore(release): 0.6.14 2021-08-05 01:20:13 +01:00
1fc7faac1f fix(build): silly typo 2021-08-05 01:19:39 +01:00
786d253df6 chore(plan): do not modify archive behavior based on plan disk image
This allows archive creation (or not) to still be controlled via the
--[no-]archive flag.
2021-08-05 00:21:17 +01:00
228ae0939c chore(release): 0.6.13 2021-08-04 23:59:58 +01:00
ac943c430c fix(native_comp): add option to enable/disable relinking *.eln files
Relinking the /usr/local/lib/gcc/10/libgcc_s.1.dylib shared library
within bundled *.eln files is still causing issues with code signing, so
I'm adding an option to toggle *.eln file re-linking on/off, with it on
by default.
2021-08-04 23:58:27 +01:00
bc3923c9ca chore(release): 0.6.12 2021-08-03 00:19:21 +01:00
e6b1e5a554 fix(sign): resolve signing issue caused by re-linking shared lib in *.eln files
When shared libs are stored in `Contents/Frameworks`, the re-link path
for `/usr/local/lib/gcc/11/libgcc_s.1.dylib` within bundled *.eln files
becomes `@executable_path/../Frameworks/libgcc_s.1.dylib`, which seems to
not leave enough space in the *.eln binary header to add a code
signature with codesign.

This used to work when shared libraries were bundled into
`Contents/MacOS/lib`, leading to a shorter relink path of
`@executable_path/lib/libgcc_s.1.dylib`, which does leave enough space
to add a code signature to *.eln files.
2021-08-03 00:13:10 +01:00
94625fce38 chore(release): 0.6.11 2021-07-17 13:08:10 +01:00
b03343f506 fix(native-comp): fix re-linking and signing issue with *.eln files
With the recent move of shared libraries and native lisp *.eln files to
Contents/Frameworks, the re-linking paths became longer, causing code
signing to fail with headerpad errors. This change ensures there's
enough space within binary files for longer shared library relink paths,
and code signing payloads.
2021-07-17 13:04:33 +01:00
b1896d4a4f chore(release): 0.6.10 2021-07-17 00:20:42 +01:00
9d32509c61 fix(native-comp): *.eln files were not being found during shared lib embedding 2021-07-16 21:00:24 +01:00
1c2745cd36 docs(readme): mention binary builds repo 2021-07-10 21:19:11 +01:00
80a0d55b24 chore(release): 0.6.9 2021-07-04 23:28:28 +01:00
fd0ec4d772 fix(plan): correctly parse --test-release-type flag
The --test-release-type flag was essentially broken and ignored, always
creating a prerelease release for test builds. Now it can also produce
draft releases.
2021-07-04 23:27:00 +01:00
c0c809a86a style(lint): fix linting complaint 2021-07-03 02:39:01 +01:00
cb63806262 feat(release): add bulk edit command to quickly change multiple GitHub releases 2021-07-03 02:36:15 +01:00
6d7ab95ca2 chore(release): 0.6.8 2021-07-03 00:19:26 +01:00
f4d6e3a56d feat(builds): add support for stable builds
Stable builds are based off of release git tags in Emacs' git
repo. Examples of what release tags look like:

- emacs-26.1
- emacs-26.2
- emacs-26.3
- emacs-27.1
- emacs-27.2

When the specified git ref looks like a stable release, the plan command
will generate a release a different and simpler release name that does
not include the date, git sha or ref. Instead, for "emacs-27.2" for
example, the emacs-builds release name will be "Emacs-27.2".

The "build name", used for naming the disk image, still retains the same
format as the nightly builds.

Also, non-stable releases are now marked as pre-release on GitHub by
default.

The reason for the different release name format for stable builds is
both to separate them, but also to make it easier to keep the version of
the homebrew cask as simply "27.2".
2021-07-03 00:11:59 +01:00
3f1059940d chore(release): 0.6.7 2021-07-02 16:50:25 +01:00
5c722e36c5 feat(bundle): move bundled shared libraries to Contents/Frameworks
The Frameworks folder is the recommended location to store shared
libraries within macOS application bundles. Previously we stored them in
Contents/MacOS/lib.

Latest nightly builds already store all *.eln files under the Frameworks
folder, so it seemed like a good time to make the change with the
library bundler/embedder too.
2021-07-02 16:49:32 +01:00
11 changed files with 468 additions and 41 deletions

View File

@@ -2,6 +2,67 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.6.14](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.13...v0.6.14) (2021-08-05)
### Bug Fixes
* **build:** silly typo ([1fc7faa](https://github.com/jimeh/build-emacs-for-macos/commit/1fc7faac1f040466fa4474a873d2290273780ee2))
### [0.6.13](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.12...v0.6.13) (2021-08-04)
### Bug Fixes
* **native_comp:** add option to enable/disable relinking *.eln files ([ac943c4](https://github.com/jimeh/build-emacs-for-macos/commit/ac943c430c58e0761ac44e8d25d4d55a461d01a2))
### [0.6.12](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.11...v0.6.12) (2021-08-02)
### Bug Fixes
* **sign:** resolve signing issue caused by re-linking shared lib in *.eln files ([e6b1e5a](https://github.com/jimeh/build-emacs-for-macos/commit/e6b1e5a554fd0f776bd01c17cfb1ebbbdf7a7831))
### [0.6.11](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.10...v0.6.11) (2021-07-17)
### Bug Fixes
* **native-comp:** fix re-linking and signing issue with *.eln files ([b03343f](https://github.com/jimeh/build-emacs-for-macos/commit/b03343f506aa3ceabdfa03f8a2916b2db4873f3f))
### [0.6.10](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.9...v0.6.10) (2021-07-16)
### Bug Fixes
* **native-comp:** *.eln files were not being found during shared lib embedding ([9d32509](https://github.com/jimeh/build-emacs-for-macos/commit/9d32509c615076618957cc47c82f6e9d8f972fe7))
### [0.6.9](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.8...v0.6.9) (2021-07-04)
### Features
* **release:** add bulk edit command to quickly change multiple GitHub releases ([cb63806](https://github.com/jimeh/build-emacs-for-macos/commit/cb638062625d9bc3eee12515067fb09e05a08414))
### Bug Fixes
* **plan:** correctly parse --test-release-type flag ([fd0ec4d](https://github.com/jimeh/build-emacs-for-macos/commit/fd0ec4d772dd3da93afc234fb3024220b2099c88))
### [0.6.8](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.7...v0.6.8) (2021-07-02)
### Features
* **builds:** add support for stable builds ([f4d6e3a](https://github.com/jimeh/build-emacs-for-macos/commit/f4d6e3a56d2c15b0c86af18e8d16bebbeb92a8ab))
### [0.6.7](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.6...v0.6.7) (2021-07-02)
### Features
* **bundle:** move bundled shared libraries to Contents/Frameworks ([5c722e3](https://github.com/jimeh/build-emacs-for-macos/commit/5c722e36c571aa7bf558b7f210c011f12d8d8a1c))
### [0.6.6](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.5...v0.6.6) (2021-07-01)
### [0.6.5](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.4...v0.6.5) (2021-07-01)

View File

@@ -45,6 +45,11 @@ The build produced does have some limitations:
that built the application will yield warnings. If you want to make a signed
Emacs.app, google is you friend for finding signing instructions.
## Binary Builds
Nightly and stable binary builds produced with this build script are available
from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
## Requirements
- [Xcode](https://apps.apple.com/gb/app/xcode/id497799835?mt=12)

View File

@@ -11,6 +11,7 @@ require 'net/http'
require 'optparse'
require 'pathname'
require 'time'
require 'tmpdir'
require 'uri'
require 'yaml'
@@ -106,7 +107,7 @@ class Build
handle_native_lisp(app)
add_cli_helper(app)
LibEmbedder.new(app, brew_dir, extra_libs).embed
LibEmbedder.new(app, brew_dir, extra_libs, options[:relink_eln]).embed
GccLibEmbedder.new(app, gcc_info).embed if options[:native_comp]
archive_build(build_dir) if options[:archive]
@@ -132,10 +133,6 @@ class Build
@archive_filename = plan.dig('output', 'archive')
end
if plan.dig('output', 'disk_image') || !plan.dig('output', 'archive')
options[:archive] = false
end
@build_name = plan.dig('build', 'name') if plan.dig('build', 'name')
end
@@ -156,11 +153,22 @@ class Build
end
def extra_libs
@extra_libs ||= [
return @extra_libs if @extra_libs
libs = [
File.join(brew_dir, 'opt/expat/lib/libexpat.1.dylib'),
File.join(brew_dir, 'opt/libiconv/lib/libiconv.2.dylib'),
File.join(brew_dir, 'opt/zlib/lib/libz.1.dylib')
]
if options[:native_comp]
libgcc_s = File.join(
brew_dir, 'lib', 'gcc', gcc_info.major_version, 'libgcc_s.1.dylib'
)
libs << libgcc_s if File.exist?(libgcc_s)
end
@extra_libs = libs
end
def download_tarball(sha)
@@ -293,6 +301,8 @@ class Build
"-L#{gcc_info.libgccjit_lib_dir}",
"-I#{File.join(gcc_info.root_dir, 'include')}",
"-I#{File.join(gcc_info.libgccjit_root_dir, 'include')}",
# Ensure library re-linking and code signing will work after building.
'-Wl,-headerpad_max_install_names',
ENV['LDFLAGS']
].compact.join(' ')
@@ -735,8 +745,6 @@ class AbstractEmbedder
@app = app
end
private
def invocation_dir
File.join(app, 'Contents', 'MacOS')
end
@@ -754,7 +762,7 @@ class LibEmbedder < AbstractEmbedder
attr_reader :lib_source
attr_reader :extra_libs
def initialize(app, lib_source, extra_libs = [])
def initialize(app, lib_source, extra_libs = [], embed_eln_files = true)
super(app)
@lib_source = lib_source
@@ -776,7 +784,7 @@ class LibEmbedder < AbstractEmbedder
rel_path = Pathname.new(lib_dir).relative_path_from(
Pathname.new(File.dirname(binary))
).to_s
eln_files.each { |f| copy_libs(f, rel_path) }
eln_files.each { |f| copy_libs(f, rel_path) } if embed_eln_files
end
end
end
@@ -784,19 +792,7 @@ class LibEmbedder < AbstractEmbedder
private
def eln_files
@eln_files ||= Dir[
File.join(
app, 'Contents', 'Resources', 'native-lisp', '**', '*.eln'
),
File.join(
app, 'Contents', 'MacOS', 'lib', 'emacs', '**',
'native-lisp', '**', '*.eln'
),
File.join(
app, 'Contents', 'MacOS', 'libexec', 'emacs', '**',
'eln-cache', '**', '*.eln'
)
]
@eln_files ||= Dir[File.join(app, 'Contents', '**', '*.eln')]
end
def copy_libs(exe, rel_path = nil)
@@ -902,15 +898,15 @@ class GccLibEmbedder < AbstractEmbedder
end
def target_dir
File.join(invocation_dir, gcc_info.relative_lib_dir)
File.join(lib_dir, gcc_info.relative_lib_dir)
end
def source_darwin_dir
File.join(invocation_dir, gcc_info.relative_darwin_lib_dir)
File.join(lib_dir, gcc_info.relative_darwin_lib_dir)
end
def target_darwin_dir
File.join(invocation_dir, gcc_info.sanitized_relative_darwin_lib_dir)
File.join(lib_dir, gcc_info.sanitized_relative_darwin_lib_dir)
end
def source_dir
@@ -966,7 +962,21 @@ class GccInfo
def sanitized_relative_darwin_lib_dir
@sanitized_relative_darwin_lib_dir ||= File.join(
File.dirname(relative_darwin_lib_dir),
File.basename(relative_darwin_lib_dir).split('.').first
File.basename(relative_darwin_lib_dir).gsub('.', '_')
)
end
def app_bundle_relative_lib_dir
@app_bundle_relative_lib_dir ||= relative_dir(
File.join(embedder.lib_dir, relative_lib_dir),
embedder.invocation_dir
)
end
def app_bundle_relative_darwin_lib_dir
@app_bundle_relative_darwin_lib_dir ||= relative_dir(
File.join(embedder.lib_dir, sanitized_relative_darwin_lib_dir),
embedder.invocation_dir
)
end
@@ -1013,6 +1023,10 @@ class GccInfo
private
def embedder
@embedder ||= AbstractEmbedder.new(Dir.mktmpdir(['Emacs', '.app']))
end
def relative_dir(path, root)
Pathname.new(path).relative_path_from(Pathname.new(root)).to_s
end
@@ -1079,6 +1093,12 @@ if __FILE__ == $PROGRAM_NAME
cli_options[:native_full_aot] = v
end
opts.on('--[no-]relink-eln-files',
'Enable/disable re-linking shared libraries in bundled *.eln ' \
'files (default: enabled)') do |v|
cli_options[:relink_eln] = v
end
opts.on('--[no-]rsvg',
'Enable/disable SVG image support via librsvg ' \
'(default: enabled)') do |v|

View File

@@ -1,8 +1,8 @@
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 8c638312b0..87af889ef4 100644
index 638d4b274c..2599211936 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -4215,6 +4215,52 @@ native-compile-async
@@ -4224,6 +4224,52 @@ native-compile-async
(let ((load (not (not load))))
(native--compile-async files recursively load selector)))
@@ -16,10 +16,10 @@ index 8c638312b0..87af889ef4 100644
+ (devtools-dir
+ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
+ (gcc-dir (expand-file-name
+ "<%= relative_lib_dir %>"
+ "<%= app_bundle_relative_lib_dir %>"
+ invocation-directory))
+ (darwin-dir (expand-file-name
+ "<%= sanitized_relative_darwin_lib_dir %>"
+ "<%= app_bundle_relative_darwin_lib_dir %>"
+ invocation-directory))
+ (lib-paths (list)))
+

View File

@@ -19,6 +19,7 @@ import (
"github.com/hexops/gotextdiff/myers"
"github.com/hexops/gotextdiff/span"
"github.com/jimeh/build-emacs-for-macos/pkg/gh"
"github.com/jimeh/build-emacs-for-macos/pkg/release"
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
)
@@ -363,9 +364,14 @@ func (s *Updater) renderCask(
ctx context.Context,
chk *LiveCheck,
) ([]byte, error) {
releaseName := "Emacs." + chk.Version.Latest
releaseName, err := release.VersionToName(chk.Version.Latest)
if err != nil {
return nil, err
}
s.logger.Info("fetching release details", "release", releaseName)
s.logger.Info("fetching release details",
"release", releaseName, "repo", s.BuildsRepo.URL(),
)
release, resp, err := s.gh.Repositories.GetReleaseByTag(
ctx, s.BuildsRepo.Owner(), s.BuildsRepo.Name(), releaseName,
)

View File

@@ -89,7 +89,7 @@ func planAction(c *cli2.Context, opts *Options) error {
GithubToken: c.String("github-token"),
}
if c.String("test-build-type") == "draft" {
if c.String("test-release-type") == "draft" {
planOpts.TestBuildType = plan.Draft
}

View File

@@ -1,6 +1,7 @@
package cli
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -60,6 +61,7 @@ func releaseCmd() *cli2.Command {
Subcommands: []*cli2.Command{
releaseCheckCmd(),
releasePublishCmd(),
releaseBulkCmd(),
},
}
}
@@ -206,3 +208,56 @@ func releasePublishAction(
return release.Publish(c.Context, rlsOpts)
}
func releaseBulkCmd() *cli2.Command {
return &cli2.Command{
Name: "bulk",
Usage: "bulk modify GitHub releases",
ArgsUsage: "",
Flags: []cli2.Flag{
&cli2.StringFlag{
Name: "name",
Usage: "regexp pattern matching release names to modify",
},
&cli2.StringFlag{
Name: "prerelease",
Usage: "change prerelease flag, must be \"true\" or " +
"\"false\", otherwise prerelease value is not changed",
},
&cli2.BoolFlag{
Name: "dry-run",
Usage: "do not perform any changes",
},
},
Action: releaseActionWrapper(releaseBulkAction),
}
}
func releaseBulkAction(
c *cli2.Context,
opts *Options,
rOpts *releaseOptions,
) error {
bulkOpts := &release.BulkOptions{
Repository: rOpts.Repository,
NamePattern: c.String("name"),
DryRun: c.Bool("dry-run"),
GithubToken: rOpts.GithubToken,
}
switch c.String("prerelease") {
case "true":
v := true
bulkOpts.Prerelease = &v
case "false":
v := false
bulkOpts.Prerelease = &v
case "":
default:
return errors.New(
"--prerelease by me \"true\" or \"false\" when specified",
)
}
return release.Bulk(c.Context, bulkOpts)
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/jimeh/build-emacs-for-macos/pkg/commit"
"github.com/jimeh/build-emacs-for-macos/pkg/gh"
"github.com/jimeh/build-emacs-for-macos/pkg/osinfo"
"github.com/jimeh/build-emacs-for-macos/pkg/release"
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
)
@@ -64,15 +65,17 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
return nil, err
}
releaseName := fmt.Sprintf(
"Emacs.%s.%s.%s",
version := fmt.Sprintf(
"%s.%s.%s",
commitInfo.DateString(),
commitInfo.ShortSHA(),
sanitizeString(opts.Ref),
)
releaseName := fmt.Sprintf("Emacs.%s", version)
buildName := fmt.Sprintf(
"%s.%s.%s",
releaseName,
"Emacs.%s.%s.%s",
version,
sanitizeString(osInfo.Name+"-"+osInfo.MajorMinor()),
sanitizeString(osInfo.Arch),
)
@@ -92,7 +95,8 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
},
OS: osInfo,
Release: &Release{
Name: releaseName,
Name: releaseName,
Prerelease: true,
},
Output: &Output{
Directory: opts.OutputDir,
@@ -100,16 +104,28 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
},
}
// If given git ref is a stable release tag (emacs-23.2b, emacs-27.2, etc.)
// we modify release properties accordingly.
if v, err := release.GitRefToStableVersion(opts.Ref); err == nil {
plan.Release.Prerelease = false
plan.Release.Name, err = release.VersionToName(v)
if err != nil {
return nil, err
}
}
if opts.TestBuild != "" {
testName := sanitizeString(opts.TestBuild)
plan.Build.Name += ".test." + testName
plan.Release.Title = "Test Builds"
plan.Release.Name = "test-builds"
plan.Release.Prerelease = true
plan.Release.Draft = false
if opts.TestBuildType == Draft {
plan.Release.Prerelease = false
plan.Release.Draft = true
} else {
plan.Release.Prerelease = true
}
index := strings.LastIndex(diskImage, ".")

84
pkg/release/bulk.go Normal file
View File

@@ -0,0 +1,84 @@
package release
import (
"context"
"regexp"
"github.com/google/go-github/v35/github"
"github.com/hashicorp/go-hclog"
"github.com/jimeh/build-emacs-for-macos/pkg/gh"
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
)
type BulkOptions struct {
Repository *repository.Repository
NamePattern string
Prerelease *bool
DryRun bool
GithubToken string
}
func Bulk(ctx context.Context, opts *BulkOptions) error {
logger := hclog.FromContext(ctx).Named("release")
gh := gh.New(ctx, opts.GithubToken)
nameMatcher, err := regexp.Compile(opts.NamePattern)
if err != nil {
return err
}
nextPage := 1
lastPage := 1
for nextPage <= lastPage {
releases, resp, err := gh.Repositories.ListReleases(
ctx, opts.Repository.Owner(), opts.Repository.Name(),
&github.ListOptions{
Page: nextPage,
PerPage: 100,
},
)
if err != nil {
return err
}
nextPage = resp.NextPage
lastPage = resp.LastPage
for _, r := range releases {
if !nameMatcher.MatchString(r.GetName()) {
continue
}
logger.Info("match found", "release", r.GetName())
var changes []interface{}
if opts.Prerelease != nil && r.GetPrerelease() != *opts.Prerelease {
changes = append(changes, "prerelease", *opts.Prerelease)
r.Prerelease = opts.Prerelease
}
if len(changes) > 0 {
changes = append(
[]interface{}{"release", r.GetName()}, changes...,
)
logger.Info("modifying", changes...)
if !opts.DryRun {
_, _, err = gh.Repositories.EditRelease(
ctx, opts.Repository.Owner(), opts.Repository.Name(),
r.GetID(), r,
)
if err != nil {
return err
}
}
}
}
if nextPage == 0 || lastPage == 0 {
break
}
}
return nil
}

42
pkg/release/version.go Normal file
View File

@@ -0,0 +1,42 @@
package release
import (
"errors"
"fmt"
"regexp"
)
// Errors
var (
Err = errors.New("release")
ErrInvalidName = fmt.Errorf("%w: invalid name", Err)
ErrEmptyVersion = fmt.Errorf("%w: empty version", Err)
ErrNotStableRef = fmt.Errorf(
"%w: git ref is not stable tagged release", Err,
)
)
var (
stableVersion = regexp.MustCompile(`^\d+\.\d+(?:[a-z]+)?$`)
stableGetRef = regexp.MustCompile(`^emacs-(\d+\.\d+(?:[a-z]+)?)$`)
)
func VersionToName(version string) (string, error) {
if version == "" {
return "", ErrEmptyVersion
}
if stableVersion.MatchString(version) {
return "Emacs-" + version, nil
}
return "Emacs." + version, nil
}
func GitRefToStableVersion(ref string) (string, error) {
if m := stableGetRef.FindStringSubmatch(ref); len(m) > 1 {
return m[1], nil
}
return "", fmt.Errorf("%w: \"%s\"", ErrNotStableRef, ref)
}

138
pkg/release/version_test.go Normal file
View File

@@ -0,0 +1,138 @@
package release
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestVersionToName(t *testing.T) {
type args struct {
version string
}
tests := []struct {
name string
args args
want string
wantErr string
}{
{
name: "empty",
args: args{
version: "",
},
wantErr: "release: empty version",
},
{
name: "nightly",
args: args{
version: "2021-07-01.1b88404.master",
},
want: "Emacs.2021-07-01.1b88404.master",
},
{
name: "stable",
args: args{
version: "27.2",
},
want: "Emacs-27.2",
},
{
name: "stable with letter",
args: args{
version: "23.3b",
},
want: "Emacs-23.3b",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := VersionToName(tt.args.version)
assert.Equal(t, tt.want, got)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
}
})
}
}
func TestGitRefToStableVersion(t *testing.T) {
type args struct {
version string
}
tests := []struct {
name string
args args
want string
wantErr string
}{
{
name: "empty",
args: args{
version: "",
},
wantErr: "release: git ref is not stable tagged release: \"\"",
},
{
name: "master",
args: args{
version: "master",
},
wantErr: "release: git ref is not stable tagged release: " +
"\"master\"",
},
{
name: "feature",
args: args{
version: "feature/native-comp",
},
wantErr: "release: git ref is not stable tagged release: " +
"\"feature/native-comp\"",
},
{
name: "stable",
args: args{
version: "emacs-27.2",
},
want: "27.2",
},
{
name: "stable with letter",
args: args{
version: "emacs-23.3b",
},
want: "23.3b",
},
{
name: "future stable",
args: args{
version: "emacs-239.33",
},
want: "239.33",
},
{
name: "future stable with letter",
args: args{
version: "emacs-239.33c",
},
want: "239.33c",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GitRefToStableVersion(tt.args.version)
assert.Equal(t, tt.want, got)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
}
})
}
}