mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 13:06:38 +00:00
Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3d6c7fff64
|
|||
|
d08d1b9b5c
|
|||
|
6e32219c24
|
|||
|
d2548191f1
|
|||
|
8ed16b27c0
|
|||
|
14f7aa13d9
|
|||
| 59ebbdaa2b | |||
|
d98c14dde5
|
|||
|
590b0ac21a
|
|||
|
8c84ef128f
|
|||
|
8b447b6237
|
|||
|
c3d19694e7
|
|||
|
cff89684c6
|
|||
|
48a512fbce
|
|||
|
a3530c02e8
|
|||
|
138ac74ba5
|
|||
|
0ba971ef61
|
|||
|
1ae8771b2c
|
|||
|
1f2868d4b3
|
|||
|
bfa5bcf79b
|
|||
| 02d85f899f | |||
|
aeb3a75e5c
|
|||
|
|
e0fd2b16eb
|
||
|
d24ac084b7
|
|||
| 159a7333de | |||
|
b582523642
|
|||
|
4f1e748df2
|
|||
|
d984633991
|
|||
|
616f74d624
|
|||
|
d7963b7664
|
|||
|
a20a8456ab
|
|||
|
8ad3ff4f53
|
|||
|
e31f5aaf93
|
|||
|
c2fb07fdb8
|
|||
|
07e0e3dacd
|
|||
|
efddb9ef92
|
|||
| f7f4c0433a | |||
|
cbd8cb27b6
|
|||
|
656b96510a
|
|||
|
084776db6b
|
|||
|
1e6d6cc6cf
|
|||
|
68ef4c066c
|
|||
|
d476fd33ec
|
|||
| baa5930467 | |||
|
743b10c751
|
|||
|
59f1bcd3e8
|
|||
| e767e284b7 | |||
|
8129a2e93b
|
|||
|
4ae288cae3
|
|||
|
3bd78d130a
|
|||
|
fb5362ce18
|
|||
|
1a34a9504a
|
|||
| 8513521d29 | |||
|
88bbefadc6
|
|||
|
f1bf1d93b8
|
|||
|
8a467b0d43
|
|||
|
9c29f721b4
|
|||
|
4ac71ddf39
|
|||
|
d338c136db
|
|||
|
d054a17fc7
|
|||
|
4030ceb9ca
|
|||
|
ad1a7dd62c
|
|||
| 665e6addec | |||
|
7f2aba0e4e
|
|||
|
be326b22aa
|
|||
|
ef4f2ad930
|
|||
|
2293c87fc9
|
|||
|
97178bf77a
|
|||
|
591c39e629
|
|||
|
d6c99f8c60
|
|||
|
bcbd01778d
|
|||
|
5602475542
|
|||
|
67b8c5f397
|
|||
|
4dad5812fa
|
|||
|
65bdff0b6d
|
|||
|
a956dc1b42
|
|||
|
af23b63518
|
|||
| 9c20f77fe3 | |||
|
2e2f9bc98a
|
|||
|
d63cd545aa
|
|||
|
1bbfe5d3ea
|
|||
|
b4c5184cef
|
|||
|
e7a991ef92
|
|||
|
7118ed8560
|
|||
|
a71cbda511
|
|||
|
4c0eb37353
|
|||
|
b81e101ca7
|
|||
| c760ffa25e | |||
|
|
931e6ddf9e | ||
|
f17f485b9f
|
|||
|
3622df550c
|
|||
|
2a9707ec89
|
|||
|
1fc7faac1f
|
|||
|
786d253df6
|
|||
|
228ae0939c
|
|||
|
ac943c430c
|
|||
|
bc3923c9ca
|
|||
|
e6b1e5a554
|
|||
|
94625fce38
|
|||
|
b03343f506
|
|||
|
b1896d4a4f
|
|||
|
9d32509c61
|
|||
|
1c2745cd36
|
|||
|
80a0d55b24
|
|||
|
fd0ec4d772
|
|||
|
c0c809a86a
|
|||
|
cb63806262
|
|||
|
6d7ab95ca2
|
|||
|
f4d6e3a56d
|
|||
|
3f1059940d
|
|||
|
5c722e36c5
|
|||
|
f52dd8dc6d
|
|||
|
4cdbaf1ec0
|
|||
|
f3a289b11c
|
|||
|
9019e73d60
|
|||
|
28930381a8
|
|||
|
df25e54ef7
|
|||
|
6d21d1bef4
|
|||
|
99aa76b398
|
|||
|
b60ca528f8
|
|||
|
23b8236e0a
|
|||
|
56d0364099
|
|||
|
6af597b427
|
|||
|
a331457e89
|
|||
| a4171555f5 | |||
|
adbcfc6fc4
|
@@ -75,6 +75,9 @@ issues:
|
|||||||
- source: "`json:"
|
- source: "`json:"
|
||||||
linters:
|
linters:
|
||||||
- lll
|
- lll
|
||||||
|
- source: "`yaml:"
|
||||||
|
linters:
|
||||||
|
- lll
|
||||||
|
|
||||||
run:
|
run:
|
||||||
skip-dirs:
|
skip-dirs:
|
||||||
|
|||||||
23
.rubocop.yml
23
.rubocop.yml
@@ -1,9 +1,30 @@
|
|||||||
AllCops:
|
AllCops:
|
||||||
TargetRubyVersion: 2.3
|
TargetRubyVersion: 2.4
|
||||||
NewCops: enable
|
NewCops: enable
|
||||||
|
|
||||||
Layout/LineLength:
|
Layout/LineLength:
|
||||||
Max: 80
|
Max: 80
|
||||||
|
|
||||||
|
Style/AccessorGrouping:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Style/Documentation:
|
Style/Documentation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/AbcSize:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/BlockLength:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/ClassLength:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/CyclomaticComplexity:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/MethodLength:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/PerceivedComplexity:
|
||||||
|
Enabled: false
|
||||||
|
|||||||
5
Brewfile
5
Brewfile
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
brew 'autoconf'
|
brew 'autoconf'
|
||||||
brew 'coreutils'
|
brew 'coreutils'
|
||||||
brew 'curl'
|
brew 'dbus'
|
||||||
brew 'expat'
|
brew 'expat'
|
||||||
brew 'gcc'
|
brew 'gcc'
|
||||||
brew 'gmp'
|
brew 'gmp'
|
||||||
@@ -22,5 +22,8 @@ brew 'make'
|
|||||||
brew 'ncurses'
|
brew 'ncurses'
|
||||||
brew 'nettle'
|
brew 'nettle'
|
||||||
brew 'pkg-config'
|
brew 'pkg-config'
|
||||||
|
brew 'sqlite'
|
||||||
brew 'texinfo'
|
brew 'texinfo'
|
||||||
|
brew 'tree-sitter'
|
||||||
|
brew 'webp'
|
||||||
brew 'zlib'
|
brew 'zlib'
|
||||||
|
|||||||
299
CHANGELOG.md
299
CHANGELOG.md
@@ -2,6 +2,305 @@
|
|||||||
|
|
||||||
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.
|
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.42](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.41...v0.6.42) (2023-07-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* options for log-level and github source repository ([d08d1b9](https://github.com/jimeh/build-emacs-for-macos/commit/d08d1b9b5c4001302564dc8915884c465802f3b5))
|
||||||
|
|
||||||
|
### [0.6.41](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.40...v0.6.41) (2023-01-16)
|
||||||
|
|
||||||
|
### [0.6.40](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.39...v0.6.40) (2023-01-08)
|
||||||
|
|
||||||
|
### [0.6.39](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.38...v0.6.39) (2022-12-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **deprecate:** posix-spawn patch is no longer supported ([c3d1969](https://github.com/jimeh/build-emacs-for-macos/commit/c3d19694e7e4d33d462c9917683c2d63f69002f5))
|
||||||
|
* **version:** correctly handle Emacs 30.x builds ([8b447b6](https://github.com/jimeh/build-emacs-for-macos/commit/8b447b6237fbbd94c4e72af8ee79969c7cfc9363))
|
||||||
|
|
||||||
|
### [0.6.38](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.37...v0.6.38) (2022-12-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **patch:** add round-undecorated-frame from emacs-plus for 29.x ([48a512f](https://github.com/jimeh/build-emacs-for-macos/commit/48a512fbce79759caa987e2880585bd0bc937977))
|
||||||
|
* **patch:** add support for experimental poll patch from emacs-plus for 29.x ([a3530c0](https://github.com/jimeh/build-emacs-for-macos/commit/a3530c02e8260106f87d464e5cb398dcb2819460))
|
||||||
|
|
||||||
|
### [0.6.37](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.36...v0.6.37) (2022-12-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **tree-sitter:** support new --with-tree-sitter configure flag ([0ba971e](https://github.com/jimeh/build-emacs-for-macos/commit/0ba971ef61a195c91e87aa381d5d3b044461b4f6))
|
||||||
|
|
||||||
|
### [0.6.36](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.35...v0.6.36) (2022-10-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native-comp:** support new configure flag format ([1f2868d](https://github.com/jimeh/build-emacs-for-macos/commit/1f2868d4b3784e906665e9f3b6b9bba8fd72292f)), closes [#76](https://github.com/jimeh/build-emacs-for-macos/issues/76)
|
||||||
|
|
||||||
|
### [0.6.35](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.34...v0.6.35) (2022-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native-comp:** compatibility with libgccjit 12 homebrew formula ([e0fd2b1](https://github.com/jimeh/build-emacs-for-macos/commit/e0fd2b16eb91ac5a98ed4ec31f4773ab22cbd470))
|
||||||
|
|
||||||
|
### [0.6.34](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.33...v0.6.34) (2022-07-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **emacs-28:** patch configure.ac to support latest libgccjit ([b582523](https://github.com/jimeh/build-emacs-for-macos/commit/b582523642ad4c5298f5a7890edd9b48c0433684)), closes [#72](https://github.com/jimeh/build-emacs-for-macos/issues/72)
|
||||||
|
|
||||||
|
### [0.6.33](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.32...v0.6.33) (2022-04-30)
|
||||||
|
|
||||||
|
### [0.6.32](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.31...v0.6.32) (2022-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **dbus:** add flag to explicitly disable dbus support ([8ad3ff4](https://github.com/jimeh/build-emacs-for-macos/commit/8ad3ff4f53505408aa097527177032a1fd6008e0)), closes [#69](https://github.com/jimeh/build-emacs-for-macos/issues/69)
|
||||||
|
* **deps:** add sqlite brew dependency for Emacs 29.x ([a20a845](https://github.com/jimeh/build-emacs-for-macos/commit/a20a8456ab1e8de6357d5d121b9565ba65a6dd71))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native-comp:** support libgccjit 11.3.0 ([e31f5aa](https://github.com/jimeh/build-emacs-for-macos/commit/e31f5aaf9355b674c2a86b8eda35f6513f344b72)), closes [#71](https://github.com/jimeh/build-emacs-for-macos/issues/71)
|
||||||
|
|
||||||
|
### [0.6.31](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.30...v0.6.31) (2022-02-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* set source-directory correctly ([07e0e3d](https://github.com/jimeh/build-emacs-for-macos/commit/07e0e3dacddfbdb7a59aceaa2dc9cdf503ac2bcc)), closes [#68](https://github.com/jimeh/build-emacs-for-macos/issues/68)
|
||||||
|
|
||||||
|
### [0.6.30](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.29...v0.6.30) (2022-02-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **site-lisp:** add Homebrew's site-lisp directory to locallisppath ([cbd8cb2](https://github.com/jimeh/build-emacs-for-macos/commit/cbd8cb27b6ceff2e128c38cd1cc8f8380b9b4bfb))
|
||||||
|
|
||||||
|
### [0.6.29](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.28...v0.6.29) (2022-02-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **cask:** add support for pretest builds ([084776d](https://github.com/jimeh/build-emacs-for-macos/commit/084776db6b7e61958088d7b2a2588e9889e60c21))
|
||||||
|
|
||||||
|
### [0.6.28](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.27...v0.6.28) (2022-01-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **build:** add dbus dependency to enable support in Emacs builds ([68ef4c0](https://github.com/jimeh/build-emacs-for-macos/commit/68ef4c066c3fd1a7337198e8f773866088b4f481))
|
||||||
|
|
||||||
|
### [0.6.27](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.26...v0.6.27) (2021-12-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **plan:** add support for pretest and release candidate builds ([743b10c](https://github.com/jimeh/build-emacs-for-macos/commit/743b10c751e146ec7569f39a475c20a0489955f4))
|
||||||
|
|
||||||
|
### [0.6.26](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.25...v0.6.26) (2021-11-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **build:** re-link eln files by default again ([4ae288c](https://github.com/jimeh/build-emacs-for-macos/commit/4ae288cae34c5e1d291dad7b6b654fe37c4a221f))
|
||||||
|
* **native-comp:** no longer require gcc homebrew formula ([3bd78d1](https://github.com/jimeh/build-emacs-for-macos/commit/3bd78d130a5419a6530a7d30e271569e501870fb)), closes [#53](https://github.com/jimeh/build-emacs-for-macos/issues/53)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **embed:** relink shared libraries with [@rpath](https://github.com/rpath) instead of [@executable](https://github.com/executable)_path ([fb5362c](https://github.com/jimeh/build-emacs-for-macos/commit/fb5362ce183ce43e52afcc0fc721cf2145f9c85b))
|
||||||
|
|
||||||
|
### [0.6.25](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.24...v0.6.25) (2021-11-25)
|
||||||
|
|
||||||
|
### [0.6.24](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.23...v0.6.24) (2021-11-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **embedding:** embedding GCC fails when paths do not require sanitizing ([8a467b0](https://github.com/jimeh/build-emacs-for-macos/commit/8a467b0d43140f6956d53c27e2319ae1b572868c))
|
||||||
|
|
||||||
|
### [0.6.23](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.22...v0.6.23) (2021-11-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **build:** do not re-link eln files by default ([d338c13](https://github.com/jimeh/build-emacs-for-macos/commit/d338c136db8acc4378154cf66ed7db5462787602)), closes [#60](https://github.com/jimeh/build-emacs-for-macos/issues/60)
|
||||||
|
|
||||||
|
### [0.6.22](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.21...v0.6.22) (2021-11-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **patch:** add support for posix-spawn patch from emacs-plus ([4030ceb](https://github.com/jimeh/build-emacs-for-macos/commit/4030ceb9cab6749af3c28161ac97caec90a8aed0))
|
||||||
|
|
||||||
|
### [0.6.21](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.20...v0.6.21) (2021-10-27)
|
||||||
|
|
||||||
|
### [0.6.20](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.19...v0.6.20) (2021-10-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **notarization:** explicitly only copy *.c and *.h C source files ([591c39e](https://github.com/jimeh/build-emacs-for-macos/commit/591c39e629c9556adcf296cd5c15dd0b17c4d986))
|
||||||
|
|
||||||
|
### [0.6.19](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.18...v0.6.19) (2021-10-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **patch:** resolve emacs-29 symlink patches to their real URL ([bcbd017](https://github.com/jimeh/build-emacs-for-macos/commit/bcbd01778d416b99205c51f348a543489889f66d))
|
||||||
|
|
||||||
|
### [0.6.18](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.17...v0.6.18) (2021-10-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **docs:** embed C source files and set source-directory accordingly ([67b8c5f](https://github.com/jimeh/build-emacs-for-macos/commit/67b8c5f3974e178e31519846d46af82d9770ad6e))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **patches:** correctly use emacs 28.x and 29.x patches ([4dad581](https://github.com/jimeh/build-emacs-for-macos/commit/4dad5812fa2b67adc7262a778829013995a904bc))
|
||||||
|
|
||||||
|
### [0.6.17](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.16...v0.6.17) (2021-10-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **release:** tweak GitHub release description ([a956dc1](https://github.com/jimeh/build-emacs-for-macos/commit/a956dc1b42b2648e2663f5b48c72d7428fe75f19))
|
||||||
|
|
||||||
|
### [0.6.16](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.15...v0.6.16) (2021-10-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **build:** handle macOS Big Sur and later version number ([2e2f9bc](https://github.com/jimeh/build-emacs-for-macos/commit/2e2f9bc98acdc972a22add3d1015bd80cad20b41))
|
||||||
|
* **cask:** make cask template helpers more flexible ([d63cd54](https://github.com/jimeh/build-emacs-for-macos/commit/d63cd545aab3a35e0cbbbcabd862525acbc414b8))
|
||||||
|
* **plan:** allow build plan to be output as YAML or JSON ([1bbfe5d](https://github.com/jimeh/build-emacs-for-macos/commit/1bbfe5d3ea810215b417e5b80d2902f03d68f366))
|
||||||
|
* **release:** add description to GitHub Releases ([7118ed8](https://github.com/jimeh/build-emacs-for-macos/commit/7118ed856053de06ddcdfba2a2d6fa40f58c17ab))
|
||||||
|
* **release:** force-replace existing asset files by default ([e7a991e](https://github.com/jimeh/build-emacs-for-macos/commit/e7a991ef92a5c546106a8badaf9c60247a1397b5))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **release:** publish arguments are not handled as asset files to upload ([b4c5184](https://github.com/jimeh/build-emacs-for-macos/commit/b4c5184cefe43fdc54b1ad5c8a1970f104137644))
|
||||||
|
|
||||||
|
### [0.6.15](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.14...v0.6.15) (2021-08-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **build:** another --relink-eln-files flag fix ([3622df5](https://github.com/jimeh/build-emacs-for-macos/commit/3622df550c72fc9da70235005239b278b5822cf6))
|
||||||
|
|
||||||
|
### [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)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native_comp:** improve handling of *.eln files in .app bundle ([9019e73](https://github.com/jimeh/build-emacs-for-macos/commit/9019e73d606f0379f988f46d6008770f8f3f7a51))
|
||||||
|
|
||||||
|
### [0.6.4](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.3...v0.6.4) (2021-06-30)
|
||||||
|
|
||||||
|
### [0.6.3](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.2...v0.6.3) (2021-06-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **patches:** correctly set ref when loading a build plan YAML ([99aa76b](https://github.com/jimeh/build-emacs-for-macos/commit/99aa76b3985195c310a20bafa19a8c7a4c8558fd))
|
||||||
|
|
||||||
|
### [0.6.2](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.1...v0.6.2) (2021-06-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **native_comp:** patch Emacs.pdmp for customized native-lisp paths ([23b8236](https://github.com/jimeh/build-emacs-for-macos/commit/23b8236e0a66fb09810e8422bedf02f7192a53e4))
|
||||||
|
|
||||||
|
### [0.6.1](https://github.com/jimeh/build-emacs-for-macos/compare/v0.6.0...v0.6.1) (2021-06-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **cask:** add missing --force flag to cask update command ([6af597b](https://github.com/jimeh/build-emacs-for-macos/commit/6af597b4271341f9796c3d9c356de9918e0f6f85))
|
||||||
|
|
||||||
|
## [0.6.0](https://github.com/jimeh/build-emacs-for-macos/compare/v0.5.2...v0.6.0) (2021-06-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **cask:** add cask update command to manage cask formula ([adbcfc6](https://github.com/jimeh/build-emacs-for-macos/commit/adbcfc6fc433fcc99b10dc5ccb51ba458333fa9c))
|
||||||
|
|
||||||
### [0.5.2](https://github.com/jimeh/build-emacs-for-macos/compare/v0.5.1...v0.5.2) (2021-06-27)
|
### [0.5.2](https://github.com/jimeh/build-emacs-for-macos/compare/v0.5.1...v0.5.2) (2021-06-27)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -17,21 +17,10 @@ Use this script at your own risk.
|
|||||||
built from the `master` branch. This script allows you to choose any branch,
|
built from the `master` branch. This script allows you to choose any branch,
|
||||||
tag, or git ref you want.
|
tag, or git ref you want.
|
||||||
|
|
||||||
## Status
|
## Binary Builds
|
||||||
|
|
||||||
As of writing (2021-04-25) it works for me on my machine. Your luck may vary.
|
Nightly and stable binary builds produced with this build script are available
|
||||||
|
from [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds).
|
||||||
I have successfully built:
|
|
||||||
|
|
||||||
- `emacs-27.1` release git tag
|
|
||||||
- `master` branch (Emacs 28.x)
|
|
||||||
- `feature/native-comp` branch (Emacs 28.x)
|
|
||||||
|
|
||||||
For reference, my machine is:
|
|
||||||
|
|
||||||
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
|
|
||||||
- macOS Big Sur 11.2.3 (20D91)
|
|
||||||
- Xcode 12.4 (12D4e)
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
@@ -41,9 +30,9 @@ The build produced does have some limitations:
|
|||||||
application will be that of the machine it was built on.
|
application will be that of the machine it was built on.
|
||||||
- The minimum required macOS version of the built application will be the same
|
- The minimum required macOS version of the built application will be the same
|
||||||
as that of the machine it was built on.
|
as that of the machine it was built on.
|
||||||
- The application is not signed, so running it on machines other than the one
|
- The application is not signed automatically, but the CLI tool used to sign the
|
||||||
that built the application will yield warnings. If you want to make a signed
|
nightly builds is available. Run `go run ./cmd/emacs-builder package --help`
|
||||||
Emacs.app, google is you friend for finding signing instructions.
|
for details. More detailed instructions will come soon.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -61,6 +50,26 @@ The build produced does have some limitations:
|
|||||||
brew install ruby
|
brew install ruby
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
As of writing (2021-11-27) it works for me on my machine and for the nightly
|
||||||
|
builds in [jimeh/emacs-builds](https://github.com/jimeh/emacs-builds). Your luck
|
||||||
|
may vary.
|
||||||
|
|
||||||
|
I have successfully built:
|
||||||
|
|
||||||
|
- `emacs-28` release branch
|
||||||
|
- `master` branch (Emacs 29.x)
|
||||||
|
|
||||||
|
For reference, my machine is:
|
||||||
|
|
||||||
|
- 13-inch MacBook Pro (2020), 10th-gen 2.3 GHz Quad-Core Intel Core i7 (4c/8t)
|
||||||
|
- macOS Monterey 12.0.1 (21A559)
|
||||||
|
- Xcode 13.1 (13A1030d)
|
||||||
|
|
||||||
|
Nightly builds are built with GitHub Actions on GitHub-hosted runners, using
|
||||||
|
`macos-10.15`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -76,8 +85,10 @@ Options:
|
|||||||
--[no-]native-comp Enable/disable native-comp (default: enabled if supported)
|
--[no-]native-comp Enable/disable native-comp (default: enabled if supported)
|
||||||
--[no-]native-march Enable/disable -march=native CFLAG(default: disabled)
|
--[no-]native-march Enable/disable -march=native CFLAG(default: disabled)
|
||||||
--[no-]native-full-aot Enable/disable NATIVE_FULL_AOT / Ahead of Time compilation (default: disabled)
|
--[no-]native-full-aot Enable/disable NATIVE_FULL_AOT / Ahead of Time compilation (default: disabled)
|
||||||
|
--[no-]relink-eln-files Enable/disable re-linking shared libraries in bundled *.eln files (default: enabled)
|
||||||
--[no-]rsvg Enable/disable SVG image support via librsvg (default: enabled)
|
--[no-]rsvg Enable/disable SVG image support via librsvg (default: enabled)
|
||||||
--no-titlebar Apply no-titlebar patch (default: disabled)
|
--no-titlebar Apply no-titlebar patch (default: disabled)
|
||||||
|
--posix-spawn Apply posix-spawn patch (default: disabled)
|
||||||
--no-frame-refocus Apply no-frame-refocus patch (default: disabled)
|
--no-frame-refocus Apply no-frame-refocus patch (default: disabled)
|
||||||
--[no-]github-auth Make authenticated GitHub API requests if GITHUB_TOKEN environment variable is set.(default: enabled)
|
--[no-]github-auth Make authenticated GitHub API requests if GITHUB_TOKEN environment variable is set.(default: enabled)
|
||||||
--work-dir DIR Specify a working directory where tarballs, sources, and builds will be stored and worked with
|
--work-dir DIR Specify a working directory where tarballs, sources, and builds will be stored and worked with
|
||||||
@@ -85,7 +96,8 @@ Options:
|
|||||||
--build-name NAME Override generated build name
|
--build-name NAME Override generated build name
|
||||||
--dist-include x,y,z List of extra files to copy from Emacs source into build folder/archive (default: COPYING)
|
--dist-include x,y,z List of extra files to copy from Emacs source into build folder/archive (default: COPYING)
|
||||||
--[no-]archive Enable/disable creating *.tbz archive (default: enabled)
|
--[no-]archive Enable/disable creating *.tbz archive (default: enabled)
|
||||||
--[no-]archive-keep Enable/disable keeping source folder for archive (default: disabled)
|
--[no-]archive-keep-build-dir
|
||||||
|
Enable/disable keeping source folder for archive (default: disabled)
|
||||||
--plan FILE Follow given plan file, instead of using given git ref/sha
|
--plan FILE Follow given plan file, instead of using given git ref/sha
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
3
go.mod
3
go.mod
@@ -13,9 +13,10 @@ require (
|
|||||||
github.com/hashicorp/go-hclog v0.16.1
|
github.com/hashicorp/go-hclog v0.16.1
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||||
|
github.com/hexops/gotextdiff v1.0.3
|
||||||
github.com/jimeh/undent v1.1.0
|
github.com/jimeh/undent v1.1.0
|
||||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||||
github.com/mitchellh/gon v0.2.3
|
github.com/mitchellh/gon v0.2.5
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/urfave/cli/v2 v2.3.0
|
github.com/urfave/cli/v2 v2.3.0
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -136,6 +136,8 @@ github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER
|
|||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
|
github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
|
||||||
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
|
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jimeh/undent v1.1.0 h1:Cge7P4Ws6buy0SVuHBluY/aOKdFuJUMzoJswfAHZ4zE=
|
github.com/jimeh/undent v1.1.0 h1:Cge7P4Ws6buy0SVuHBluY/aOKdFuJUMzoJswfAHZ4zE=
|
||||||
@@ -158,8 +160,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
|||||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/gon v0.2.3 h1:fObN7hD14VacGG++t27GzTW6opP0lwI7TsgTPL55wBo=
|
github.com/mitchellh/gon v0.2.5 h1:mVWtqTzV03W0avJqmqjk9M0qls3TDUXfc9ETJaPIOWY=
|
||||||
github.com/mitchellh/gon v0.2.3/go.mod h1:Ua18ZhqjZHg8VyqZo8kNHAY331ntV6nNJ9mT3s2mIo8=
|
github.com/mitchellh/gon v0.2.5/go.mod h1:Ua18ZhqjZHg8VyqZo8kNHAY331ntV6nNJ9mT3s2mIo8=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
resolve_link() {
|
resolve_link() {
|
||||||
"$(type -p greadlink readlink | head -1)" "$1"
|
"$(command -v greadlink || command -v readlink)" "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
abs_dirname() {
|
abs_dirname() {
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
|
|
||||||
index 8c638312b0..87af889ef4 100644
|
|
||||||
--- a/lisp/emacs-lisp/comp.el
|
|
||||||
+++ b/lisp/emacs-lisp/comp.el
|
|
||||||
@@ -4215,6 +4215,52 @@ native-compile-async
|
|
||||||
(let ((load (not (not load))))
|
|
||||||
(native--compile-async files recursively load selector)))
|
|
||||||
|
|
||||||
+;;;###autoload
|
|
||||||
+(defun native-compile-setup-environment-variables (&rest _args)
|
|
||||||
+ "Ensure LIBRARY_PATH is set correctly when libgccjit is bundled."
|
|
||||||
+ (when (and (eq system-type 'darwin)
|
|
||||||
+ (string-match-p "\.app\/Contents\/MacOS\/?$"
|
|
||||||
+ invocation-directory))
|
|
||||||
+ (let* ((library-path-env (getenv "LIBRARY_PATH"))
|
|
||||||
+ (devtools-dir
|
|
||||||
+ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib")
|
|
||||||
+ (gcc-dir (expand-file-name
|
|
||||||
+ "<%= relative_lib_dir %>"
|
|
||||||
+ invocation-directory))
|
|
||||||
+ (darwin-dir (expand-file-name
|
|
||||||
+ "<%= sanitized_relative_darwin_lib_dir %>"
|
|
||||||
+ invocation-directory))
|
|
||||||
+ (lib-paths (list)))
|
|
||||||
+
|
|
||||||
+ (if library-path-env
|
|
||||||
+ (push library-path-env lib-paths))
|
|
||||||
+ (if (file-directory-p devtools-dir)
|
|
||||||
+ (push devtools-dir lib-paths))
|
|
||||||
+ (push darwin-dir lib-paths)
|
|
||||||
+ (push gcc-dir lib-paths)
|
|
||||||
+
|
|
||||||
+ (setenv "LIBRARY_PATH" (mapconcat 'identity lib-paths ":"))))
|
|
||||||
+
|
|
||||||
+ ;; Remove advice, as it only needs to run once.
|
|
||||||
+ (advice-remove 'native-compile
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+ (advice-remove 'comp--native-compile
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+ (advice-remove 'native-compile-async
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+ (advice-remove 'native--compile-async
|
|
||||||
+ 'native-compile-setup-environment-variables))
|
|
||||||
+
|
|
||||||
+;; Ensure environment setup runs before any native compilation.
|
|
||||||
+(advice-add 'native-compile :before
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+(advice-add 'comp--native-compile :before
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+(advice-add 'native-compile-async :before
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+(advice-add 'native--compile-async :before
|
|
||||||
+ 'native-compile-setup-environment-variables)
|
|
||||||
+
|
|
||||||
(provide 'comp)
|
|
||||||
|
|
||||||
;; LocalWords: limplified limplified limplification limplify Limple LIMPLE libgccjit elc eln
|
|
||||||
13
pkg/cask/live_check.go
Normal file
13
pkg/cask/live_check.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package cask
|
||||||
|
|
||||||
|
type LiveCheck struct {
|
||||||
|
Cask string `json:"cask"`
|
||||||
|
Version LiveCheckVersion `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LiveCheckVersion struct {
|
||||||
|
Current string `json:"current"`
|
||||||
|
Latest string `json:"latest"`
|
||||||
|
Outdated bool `json:"outdated"`
|
||||||
|
NewerThanUpstream bool `json:"newer_than_upstream"`
|
||||||
|
}
|
||||||
66
pkg/cask/release_info.go
Normal file
66
pkg/cask/release_info.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package cask
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReleaseInfo struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
Assets map[string]*ReleaseAsset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReleaseInfo) Asset(needles ...string) *ReleaseAsset {
|
||||||
|
if len(needles) == 1 {
|
||||||
|
if a, ok := s.Assets[needles[0]]; ok {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dirty and inefficient way to ensure assets are searched in a predictable
|
||||||
|
// order.
|
||||||
|
var assets []*ReleaseAsset
|
||||||
|
for _, a := range s.Assets {
|
||||||
|
assets = append(assets, a)
|
||||||
|
}
|
||||||
|
sort.SliceStable(assets, func(i, j int) bool {
|
||||||
|
return assets[i].Filename < assets[j].Filename
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, a := range assets {
|
||||||
|
for _, needle := range needles {
|
||||||
|
if !strings.Contains(a.Filename, needle) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReleaseInfo) DownloadURL(needles ...string) string {
|
||||||
|
a := s.Asset(needles...)
|
||||||
|
if a == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.DownloadURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReleaseInfo) SHA256(needles ...string) string {
|
||||||
|
a := s.Asset(needles...)
|
||||||
|
if a == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.SHA256
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReleaseAsset struct {
|
||||||
|
Filename string
|
||||||
|
DownloadURL string
|
||||||
|
SHA256 string
|
||||||
|
}
|
||||||
491
pkg/cask/update.go
Normal file
491
pkg/cask/update.go
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
package cask
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v35/github"
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/hexops/gotextdiff"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error vars
|
||||||
|
var (
|
||||||
|
Err = errors.New("cask")
|
||||||
|
ErrReleaseNotFound = fmt.Errorf("%w: release not found", Err)
|
||||||
|
|
||||||
|
ErrFailedSHA256Parse = fmt.Errorf(
|
||||||
|
"%w: failed to parse SHA256 from asset", Err,
|
||||||
|
)
|
||||||
|
ErrFailedSHA256Download = fmt.Errorf(
|
||||||
|
"%w: failed to download SHA256 asset", Err,
|
||||||
|
)
|
||||||
|
ErrNoTapOrOutput = fmt.Errorf(
|
||||||
|
"%w: no tap repository or output directory specified", Err,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateOptions struct {
|
||||||
|
// BuildsRepo is the GitHub repository containing binary releases.
|
||||||
|
BuildsRepo *repository.Repository
|
||||||
|
|
||||||
|
// TapRepo is the GitHub repository to update the casks in.
|
||||||
|
TapRepo *repository.Repository
|
||||||
|
|
||||||
|
// Ref is the git ref to apply cask updates on top of. Default branch will
|
||||||
|
// be used if empty.
|
||||||
|
Ref string
|
||||||
|
|
||||||
|
// OutputDir specifies a directory to write cask files to. When set, tap
|
||||||
|
// repository is ignored and no changes will be committed directly against
|
||||||
|
// any specified tap repository.
|
||||||
|
OutputDir string
|
||||||
|
|
||||||
|
// Force update will ignore the outdated live check flag, and process all
|
||||||
|
// casks regardless. But it will only update the cask in question if the
|
||||||
|
// resulting output cask is different.
|
||||||
|
Force bool
|
||||||
|
|
||||||
|
// TemplatesDir is the directory where cask templates are located.
|
||||||
|
TemplatesDir string
|
||||||
|
|
||||||
|
LiveChecks []*LiveCheck
|
||||||
|
|
||||||
|
GithubToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Updater struct {
|
||||||
|
BuildsRepo *repository.Repository
|
||||||
|
TapRepo *repository.Repository
|
||||||
|
Ref string
|
||||||
|
OutputDir string
|
||||||
|
TemplatesDir string
|
||||||
|
|
||||||
|
logger hclog.Logger
|
||||||
|
gh *github.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func Update(ctx context.Context, opts *UpdateOptions) error {
|
||||||
|
updater := &Updater{
|
||||||
|
BuildsRepo: opts.BuildsRepo,
|
||||||
|
TapRepo: opts.TapRepo,
|
||||||
|
Ref: opts.Ref,
|
||||||
|
OutputDir: opts.OutputDir,
|
||||||
|
TemplatesDir: opts.TemplatesDir,
|
||||||
|
logger: hclog.FromContext(ctx).Named("cask"),
|
||||||
|
gh: gh.New(ctx, opts.GithubToken),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, chk := range opts.LiveChecks {
|
||||||
|
err := updater.Update(ctx, chk, opts.Force)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) Update(
|
||||||
|
ctx context.Context,
|
||||||
|
chk *LiveCheck,
|
||||||
|
force bool,
|
||||||
|
) error {
|
||||||
|
if s.TapRepo == nil && s.OutputDir == "" {
|
||||||
|
return ErrNoTapOrOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
if !force && !chk.Version.Outdated {
|
||||||
|
s.logger.Info("skipping", "cask", chk.Cask, "reason", "up to date")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newCaskContent, err := s.renderCask(ctx, chk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
caskFile := chk.Cask + ".rb"
|
||||||
|
|
||||||
|
if s.OutputDir != "" {
|
||||||
|
_, err = s.putFile(
|
||||||
|
ctx, chk, filepath.Join(s.OutputDir, caskFile), newCaskContent,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.putRepoFile(
|
||||||
|
ctx, s.TapRepo, s.Ref, chk,
|
||||||
|
filepath.Join("Casks", caskFile), newCaskContent,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) putFile(
|
||||||
|
ctx context.Context,
|
||||||
|
chk *LiveCheck,
|
||||||
|
filename string,
|
||||||
|
content []byte,
|
||||||
|
) (bool, error) {
|
||||||
|
parent := filepath.Dir(filename)
|
||||||
|
s.logger.Info("processing cask update",
|
||||||
|
"output-directory", parent, "cask", chk.Cask, "file", filename,
|
||||||
|
)
|
||||||
|
|
||||||
|
err := os.MkdirAll(parent, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
existingContent, err := os.ReadFile(filename)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
infoMsg := "creating cask"
|
||||||
|
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
infoMsg = "updating cask"
|
||||||
|
if bytes.Equal(existingContent, content) {
|
||||||
|
s.logger.Info(
|
||||||
|
"skip update: no change to cask content",
|
||||||
|
"cask", chk.Cask, "file", filename,
|
||||||
|
)
|
||||||
|
|
||||||
|
s.logger.Debug(
|
||||||
|
"cask content",
|
||||||
|
"file", filename, "content", string(content),
|
||||||
|
)
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
existing := string(existingContent)
|
||||||
|
edits := myers.ComputeEdits(
|
||||||
|
span.URIFromPath(filename), existing, string(content),
|
||||||
|
)
|
||||||
|
diff := fmt.Sprint(gotextdiff.ToUnified(
|
||||||
|
filename, filename, existing, edits,
|
||||||
|
))
|
||||||
|
|
||||||
|
s.logger.Info(
|
||||||
|
infoMsg,
|
||||||
|
"cask", chk.Cask, "version", chk.Version.Latest, "file", filename,
|
||||||
|
"diff", diff,
|
||||||
|
)
|
||||||
|
|
||||||
|
s.logger.Debug(
|
||||||
|
"cask content",
|
||||||
|
"file", filename, "content", string(content),
|
||||||
|
)
|
||||||
|
|
||||||
|
err = os.WriteFile(filename, content, 0o644) //nolint:gosec
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) putRepoFile(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *repository.Repository,
|
||||||
|
ref string,
|
||||||
|
chk *LiveCheck,
|
||||||
|
filename string,
|
||||||
|
content []byte,
|
||||||
|
) (bool, error) {
|
||||||
|
s.logger.Info("processing cask update",
|
||||||
|
"tap-repo", repo.Source, "cask", chk.Cask, "file", filename,
|
||||||
|
)
|
||||||
|
repoContent, _, resp, err := s.gh.Repositories.GetContents(
|
||||||
|
ctx, repo.Owner(), repo.Name(), filename,
|
||||||
|
&github.RepositoryContentGetOptions{Ref: ref},
|
||||||
|
)
|
||||||
|
if err != nil && resp.StatusCode != http.StatusNotFound {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
|
err := s.createRepoFile(ctx, repo, chk, filename, content)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := s.updateRepoFile(
|
||||||
|
ctx, repo, repoContent, chk, filename, content,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) createRepoFile(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *repository.Repository,
|
||||||
|
chk *LiveCheck,
|
||||||
|
filename string,
|
||||||
|
content []byte,
|
||||||
|
) error {
|
||||||
|
commitMsg := fmt.Sprintf(
|
||||||
|
"feat(cask): create %s with version %s",
|
||||||
|
chk.Cask, chk.Version.Latest,
|
||||||
|
)
|
||||||
|
|
||||||
|
edits := myers.ComputeEdits(
|
||||||
|
span.URIFromPath(filename), "", string(content),
|
||||||
|
)
|
||||||
|
diff := fmt.Sprint(gotextdiff.ToUnified(filename, filename, "", edits))
|
||||||
|
|
||||||
|
s.logger.Info(
|
||||||
|
"creating cask",
|
||||||
|
"cask", chk.Cask, "version", chk.Version.Latest, "file", filename,
|
||||||
|
"diff", diff,
|
||||||
|
)
|
||||||
|
s.logger.Debug(
|
||||||
|
"cask content",
|
||||||
|
"file", filename, "content", string(content),
|
||||||
|
)
|
||||||
|
contResp, _, err := s.gh.Repositories.CreateFile(
|
||||||
|
ctx, repo.Owner(), repo.Name(), filename,
|
||||||
|
&github.RepositoryContentFileOptions{
|
||||||
|
Message: &commitMsg,
|
||||||
|
Content: content,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info(
|
||||||
|
"new commit created",
|
||||||
|
"commit", contResp.GetSHA(), "message", contResp.GetMessage(),
|
||||||
|
"url", contResp.Commit.GetHTMLURL(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) updateRepoFile(
|
||||||
|
ctx context.Context,
|
||||||
|
repo *repository.Repository,
|
||||||
|
repoContent *github.RepositoryContent,
|
||||||
|
chk *LiveCheck,
|
||||||
|
filename string,
|
||||||
|
content []byte,
|
||||||
|
) (bool, error) {
|
||||||
|
existingContent, err := repoContent.GetContent()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if existingContent == string(content) {
|
||||||
|
s.logger.Info(
|
||||||
|
"skip update: no change to cask content",
|
||||||
|
"cask", chk.Cask, "file", filename,
|
||||||
|
)
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sha := repoContent.GetSHA()
|
||||||
|
|
||||||
|
commitMsg := fmt.Sprintf(
|
||||||
|
"feat(cask): update %s to version %s",
|
||||||
|
chk.Cask, chk.Version.Latest,
|
||||||
|
)
|
||||||
|
|
||||||
|
edits := myers.ComputeEdits(
|
||||||
|
span.URIFromPath(filename), existingContent, string(content),
|
||||||
|
)
|
||||||
|
diff := fmt.Sprint(gotextdiff.ToUnified(
|
||||||
|
filename, filename, existingContent, edits,
|
||||||
|
))
|
||||||
|
|
||||||
|
s.logger.Info(
|
||||||
|
"updating cask",
|
||||||
|
"cask", chk.Cask, "version", chk.Version.Latest, "file", filename,
|
||||||
|
"diff", diff,
|
||||||
|
)
|
||||||
|
s.logger.Debug(
|
||||||
|
"cask content",
|
||||||
|
"file", filename, "content", string(content),
|
||||||
|
)
|
||||||
|
|
||||||
|
contResp, _, err := s.gh.Repositories.CreateFile(
|
||||||
|
ctx, repo.Owner(), repo.Name(), filename,
|
||||||
|
&github.RepositoryContentFileOptions{
|
||||||
|
Message: &commitMsg,
|
||||||
|
Content: content,
|
||||||
|
SHA: &sha,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info(
|
||||||
|
"new commit created",
|
||||||
|
"commit", contResp.GetSHA(), "message", contResp.GetMessage(),
|
||||||
|
"url", contResp.Commit.GetHTMLURL(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) renderCask(
|
||||||
|
ctx context.Context,
|
||||||
|
chk *LiveCheck,
|
||||||
|
) ([]byte, error) {
|
||||||
|
releaseName, err := release.VersionToName(chk.Version.Latest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if release == nil || resp.StatusCode == http.StatusNotFound {
|
||||||
|
return nil, fmt.Errorf("%w: %s", ErrReleaseNotFound, releaseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &ReleaseInfo{
|
||||||
|
Name: release.GetName(),
|
||||||
|
Version: chk.Version.Latest,
|
||||||
|
Assets: map[string]*ReleaseAsset{},
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("processing release assets")
|
||||||
|
for _, asset := range release.Assets {
|
||||||
|
filename := asset.GetName()
|
||||||
|
s.logger.Debug("processing asset", "filename", filename)
|
||||||
|
|
||||||
|
filename = strings.TrimSuffix(filename, ".sha256")
|
||||||
|
|
||||||
|
if _, ok := info.Assets[filename]; !ok {
|
||||||
|
info.Assets[filename] = &ReleaseAsset{
|
||||||
|
Filename: filename,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(asset.GetName(), ".sha256") {
|
||||||
|
s.logger.Debug("downloading *.sha256 asset to extract SHA256 value")
|
||||||
|
r, err2 := s.downloadAssetContent(ctx, asset)
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, err2
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
content := make([]byte, 64)
|
||||||
|
n, err2 := io.ReadAtLeast(r, content, 64)
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, err2
|
||||||
|
}
|
||||||
|
if n < 64 {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"%w: %s", ErrFailedSHA256Parse, asset.GetName(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
sha := string(content)[0:64]
|
||||||
|
if sha == "" {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"%w: %s", ErrFailedSHA256Parse, asset.GetName(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
info.Assets[filename].SHA256 = sha
|
||||||
|
} else {
|
||||||
|
info.Assets[filename].DownloadURL = asset.GetBrowserDownloadURL()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templateFile := filepath.Join(s.TemplatesDir, chk.Cask+".rb.tpl")
|
||||||
|
tplContent, err := os.ReadFile(templateFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl, err := template.New(chk.Cask).Parse(string(tplContent))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err = tpl.Execute(&buf, info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Updater) downloadAssetContent(
|
||||||
|
ctx context.Context,
|
||||||
|
asset *github.ReleaseAsset,
|
||||||
|
) (io.ReadCloser, error) {
|
||||||
|
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||||
|
|
||||||
|
r, downloadURL, err := s.gh.Repositories.DownloadReleaseAsset(
|
||||||
|
ctx, s.BuildsRepo.Owner(), s.BuildsRepo.Name(),
|
||||||
|
asset.GetID(), httpClient,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r == nil && downloadURL != "" {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", downloadURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:bodyclose
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r = resp.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
if r == nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"%s: %s", ErrFailedSHA256Download, asset.GetName(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
158
pkg/cli/cask.go
Normal file
158
pkg/cli/cask.go
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/cask"
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
|
||||||
|
cli2 "github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type caskOptions struct {
|
||||||
|
BuildsRepo *repository.Repository
|
||||||
|
GithubToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func caskCmd() *cli2.Command {
|
||||||
|
tokenDefaultText := ""
|
||||||
|
if len(os.Getenv("GITHUB_TOKEN")) > 0 {
|
||||||
|
tokenDefaultText = "***"
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cli2.Command{
|
||||||
|
Name: "cask",
|
||||||
|
Usage: "manage Homebrew Casks",
|
||||||
|
Flags: []cli2.Flag{
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "builds-repository",
|
||||||
|
Aliases: []string{"builds-repo", "b"},
|
||||||
|
Usage: "owner/name of GitHub repo for containing builds",
|
||||||
|
EnvVars: []string{"EMACS_BUILDS_REPOSITORY"},
|
||||||
|
Value: "jimeh/emacs-builds",
|
||||||
|
},
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "github-token",
|
||||||
|
Usage: "GitHub API Token",
|
||||||
|
EnvVars: []string{"GITHUB_TOKEN"},
|
||||||
|
DefaultText: tokenDefaultText,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Subcommands: []*cli2.Command{
|
||||||
|
caskUpdateCmd(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func caskActionWrapper(
|
||||||
|
f func(*cli2.Context, *Options, *caskOptions) error,
|
||||||
|
) func(*cli2.Context) error {
|
||||||
|
return actionWrapper(func(c *cli2.Context, opts *Options) error {
|
||||||
|
rOpts := &caskOptions{
|
||||||
|
GithubToken: c.String("github-token"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if r := c.String("builds-repository"); r != "" {
|
||||||
|
var err error
|
||||||
|
rOpts.BuildsRepo, err = repository.NewGitHub(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f(c, opts, rOpts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func caskUpdateCmd() *cli2.Command {
|
||||||
|
return &cli2.Command{
|
||||||
|
Name: "update",
|
||||||
|
Usage: "update casks based on brew livecheck result in JSON format",
|
||||||
|
ArgsUsage: "<livecheck.json>",
|
||||||
|
Flags: []cli2.Flag{
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "ref",
|
||||||
|
Usage: "git ref to create/update casks on top of in the " +
|
||||||
|
"tap repository",
|
||||||
|
EnvVars: []string{"GITHUB_REF"},
|
||||||
|
},
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "output",
|
||||||
|
Aliases: []string{"o"},
|
||||||
|
Usage: "directory to write cask files to",
|
||||||
|
},
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "tap-repository",
|
||||||
|
Aliases: []string{"tap"},
|
||||||
|
Usage: "owner/name of GitHub repo for Homebrew Tap to " +
|
||||||
|
"commit changes to if --output is not set",
|
||||||
|
EnvVars: []string{"GITHUB_REPOSITORY"},
|
||||||
|
},
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "templates-dir",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "path to directory of cask templates",
|
||||||
|
EnvVars: []string{"CASK_TEMPLATE_DIR"},
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
&cli2.BoolFlag{
|
||||||
|
Name: "force",
|
||||||
|
Aliases: []string{"f"},
|
||||||
|
Usage: "force update file even if livecheck has it marked " +
|
||||||
|
"as not outdated (does not force update if cask " +
|
||||||
|
"content is unchanged)",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: caskActionWrapper(caskUpdateAction),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func caskUpdateAction(
|
||||||
|
c *cli2.Context,
|
||||||
|
_ *Options,
|
||||||
|
cOpts *caskOptions,
|
||||||
|
) error {
|
||||||
|
updateOpts := &cask.UpdateOptions{
|
||||||
|
BuildsRepo: cOpts.BuildsRepo,
|
||||||
|
GithubToken: cOpts.GithubToken,
|
||||||
|
Ref: c.String("ref"),
|
||||||
|
OutputDir: c.String("output"),
|
||||||
|
Force: c.Bool("force"),
|
||||||
|
TemplatesDir: c.String("templates-dir"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if r := c.String("tap-repository"); r != "" {
|
||||||
|
var err error
|
||||||
|
updateOpts.TapRepo, err = repository.NewGitHub(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arg := c.Args().First()
|
||||||
|
if arg == "" {
|
||||||
|
return errors.New("no livecheck argument given")
|
||||||
|
}
|
||||||
|
|
||||||
|
if arg == "-" {
|
||||||
|
err := json.NewDecoder(c.App.Reader).Decode(&updateOpts.LiveChecks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f, err := os.Open(arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.NewDecoder(f).Decode(&updateOpts.LiveChecks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cask.Update(c.Context, updateOpts)
|
||||||
|
}
|
||||||
@@ -46,9 +46,11 @@ func New(version, commit, date string) *CLI {
|
|||||||
Commands: []*cli2.Command{
|
Commands: []*cli2.Command{
|
||||||
planCmd(),
|
planCmd(),
|
||||||
signCmd(),
|
signCmd(),
|
||||||
|
signFilesCmd(),
|
||||||
notarizeCmd(),
|
notarizeCmd(),
|
||||||
packageCmd(),
|
packageCmd(),
|
||||||
releaseCmd(),
|
releaseCmd(),
|
||||||
|
caskCmd(),
|
||||||
{
|
{
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Usage: "print the version",
|
Usage: "print the version",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func notarizeCmd() *cli2.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func notarizeAction(c *cli2.Context, opts *Options) error {
|
func notarizeAction(c *cli2.Context, _ *Options) error {
|
||||||
options := ¬arize.Options{
|
options := ¬arize.Options{
|
||||||
File: c.Args().Get(0),
|
File: c.Args().Get(0),
|
||||||
BundleID: c.String("bundle-id"),
|
BundleID: c.String("bundle-id"),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -37,6 +38,12 @@ func planCmd() *cli2.Command {
|
|||||||
Name: "sha",
|
Name: "sha",
|
||||||
Usage: "override commit SHA of specified git branch/tag",
|
Usage: "override commit SHA of specified git branch/tag",
|
||||||
},
|
},
|
||||||
|
&cli2.StringFlag{
|
||||||
|
Name: "format",
|
||||||
|
Aliases: []string{"f"},
|
||||||
|
Usage: "output format of build plan (yaml or json)",
|
||||||
|
Value: "yaml",
|
||||||
|
},
|
||||||
&cli2.StringFlag{
|
&cli2.StringFlag{
|
||||||
Name: "output",
|
Name: "output",
|
||||||
Usage: "output filename to write plan to instead of printing " +
|
Usage: "output filename to write plan to instead of printing " +
|
||||||
@@ -89,7 +96,7 @@ func planAction(c *cli2.Context, opts *Options) error {
|
|||||||
GithubToken: c.String("github-token"),
|
GithubToken: c.String("github-token"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.String("test-build-type") == "draft" {
|
if c.String("test-release-type") == "draft" {
|
||||||
planOpts.TestBuildType = plan.Draft
|
planOpts.TestBuildType = plan.Draft
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +109,18 @@ func planAction(c *cli2.Context, opts *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
planYAML, err := p.YAML()
|
format := c.String("format")
|
||||||
|
var plan string
|
||||||
|
switch format {
|
||||||
|
case "yaml", "yml":
|
||||||
|
format = "yaml"
|
||||||
|
plan, err = p.YAML()
|
||||||
|
case "json":
|
||||||
|
format = "json"
|
||||||
|
plan, err = p.JSON()
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("--format must be yaml or json")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -111,7 +129,7 @@ func planAction(c *cli2.Context, opts *Options) error {
|
|||||||
out = os.Stdout
|
out = os.Stdout
|
||||||
if f := c.String("output"); f != "" {
|
if f := c.String("output"); f != "" {
|
||||||
logger.Info("writing plan", "file", f)
|
logger.Info("writing plan", "file", f)
|
||||||
logger.Debug("content", "yaml", planYAML)
|
logger.Debug("content", format, plan)
|
||||||
out, err = os.Create(f)
|
out, err = os.Create(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -119,7 +137,7 @@ func planAction(c *cli2.Context, opts *Options) error {
|
|||||||
defer out.Close()
|
defer out.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = out.WriteString(planYAML)
|
_, err = out.WriteString(plan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -42,7 +43,7 @@ func releaseCmd() *cli2.Command {
|
|||||||
Usage: "owner/name of GitHub repo to check for release, " +
|
Usage: "owner/name of GitHub repo to check for release, " +
|
||||||
"ignored if a plan is provided",
|
"ignored if a plan is provided",
|
||||||
EnvVars: []string{"GITHUB_REPOSITORY"},
|
EnvVars: []string{"GITHUB_REPOSITORY"},
|
||||||
Value: "jimeh/emacs-builds",
|
Value: "",
|
||||||
},
|
},
|
||||||
&cli2.StringFlag{
|
&cli2.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
@@ -60,6 +61,7 @@ func releaseCmd() *cli2.Command {
|
|||||||
Subcommands: []*cli2.Command{
|
Subcommands: []*cli2.Command{
|
||||||
releaseCheckCmd(),
|
releaseCheckCmd(),
|
||||||
releasePublishCmd(),
|
releasePublishCmd(),
|
||||||
|
releaseBulkCmd(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +108,7 @@ func releaseCheckCmd() *cli2.Command {
|
|||||||
|
|
||||||
func releaseCheckAction(
|
func releaseCheckAction(
|
||||||
c *cli2.Context,
|
c *cli2.Context,
|
||||||
opts *Options,
|
_ *Options,
|
||||||
rOpts *releaseOptions,
|
rOpts *releaseOptions,
|
||||||
) error {
|
) error {
|
||||||
rlsOpts := &release.CheckOptions{
|
rlsOpts := &release.CheckOptions{
|
||||||
@@ -151,6 +153,12 @@ func releasePublishCmd() *cli2.Command {
|
|||||||
"specified",
|
"specified",
|
||||||
Value: "",
|
Value: "",
|
||||||
},
|
},
|
||||||
|
&cli2.BoolFlag{
|
||||||
|
Name: "asset-size-check",
|
||||||
|
Usage: "Do not replace existing asset files if local and " +
|
||||||
|
"remote file sizes match.",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: releaseActionWrapper(releasePublishAction),
|
Action: releaseActionWrapper(releasePublishAction),
|
||||||
}
|
}
|
||||||
@@ -158,16 +166,17 @@ func releasePublishCmd() *cli2.Command {
|
|||||||
|
|
||||||
func releasePublishAction(
|
func releasePublishAction(
|
||||||
c *cli2.Context,
|
c *cli2.Context,
|
||||||
opts *Options,
|
_ *Options,
|
||||||
rOpts *releaseOptions,
|
rOpts *releaseOptions,
|
||||||
) error {
|
) error {
|
||||||
rlsOpts := &release.PublishOptions{
|
rlsOpts := &release.PublishOptions{
|
||||||
Repository: rOpts.Repository,
|
Repository: rOpts.Repository,
|
||||||
CommitRef: c.String("release-sha"),
|
CommitRef: c.String("release-sha"),
|
||||||
ReleaseName: rOpts.Name,
|
ReleaseName: rOpts.Name,
|
||||||
ReleaseTitle: c.String("title"),
|
ReleaseTitle: c.String("title"),
|
||||||
AssetFiles: c.Args().Slice(),
|
AssetFiles: c.Args().Slice(),
|
||||||
GithubToken: rOpts.GithubToken,
|
AssetSizeCheck: c.Bool("asset-size-check"),
|
||||||
|
GithubToken: rOpts.GithubToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
rlsType := c.String("type")
|
rlsType := c.String("type")
|
||||||
@@ -182,7 +191,13 @@ func releasePublishAction(
|
|||||||
return fmt.Errorf("invalid --type \"%s\"", rlsType)
|
return fmt.Errorf("invalid --type \"%s\"", rlsType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Args().Len() > 0 {
|
||||||
|
rlsOpts.AssetFiles = c.Args().Slice()
|
||||||
|
}
|
||||||
|
|
||||||
if rOpts.Plan != nil {
|
if rOpts.Plan != nil {
|
||||||
|
rlsOpts.Source = rOpts.Plan.Source
|
||||||
|
|
||||||
if rOpts.Plan.Release != nil {
|
if rOpts.Plan.Release != nil {
|
||||||
rlsOpts.ReleaseName = rOpts.Plan.Release.Name
|
rlsOpts.ReleaseName = rOpts.Plan.Release.Name
|
||||||
rlsOpts.ReleaseTitle = rOpts.Plan.Release.Title
|
rlsOpts.ReleaseTitle = rOpts.Plan.Release.Title
|
||||||
@@ -194,7 +209,8 @@ func releasePublishAction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rOpts.Plan.Output != nil {
|
// Set asset files based on plan if no file arguments were given.
|
||||||
|
if len(rlsOpts.AssetFiles) == 0 && rOpts.Plan.Output != nil {
|
||||||
rlsOpts.AssetFiles = []string{
|
rlsOpts.AssetFiles = []string{
|
||||||
filepath.Join(
|
filepath.Join(
|
||||||
rOpts.Plan.Output.Directory,
|
rOpts.Plan.Output.Directory,
|
||||||
@@ -206,3 +222,56 @@ func releasePublishAction(
|
|||||||
|
|
||||||
return release.Publish(c.Context, rlsOpts)
|
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,
|
||||||
|
_ *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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -112,3 +112,49 @@ func signAction(c *cli2.Context, opts *Options) error {
|
|||||||
|
|
||||||
return sign.Emacs(c.Context, app, signOpts)
|
return sign.Emacs(c.Context, app, signOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signFilesCmd() *cli2.Command {
|
||||||
|
signCmd := signCmd()
|
||||||
|
|
||||||
|
var flags []cli2.Flag
|
||||||
|
for _, f := range signCmd.Flags {
|
||||||
|
n := f.Names()
|
||||||
|
if len(n) > 0 && n[0] == "plan" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = append(flags, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cli2.Command{
|
||||||
|
Name: "sign-files",
|
||||||
|
Usage: "sign files with codesign",
|
||||||
|
ArgsUsage: "<file> [<file>...]",
|
||||||
|
Hidden: true,
|
||||||
|
Flags: flags,
|
||||||
|
Action: actionWrapper(signFilesAction),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func signFilesAction(c *cli2.Context, opts *Options) error {
|
||||||
|
signOpts := &sign.Options{
|
||||||
|
Identity: c.String("sign"),
|
||||||
|
Options: c.StringSlice("options"),
|
||||||
|
Deep: c.Bool("deep"),
|
||||||
|
Timestamp: c.Bool("timestamp"),
|
||||||
|
Force: c.Bool("force"),
|
||||||
|
Verbose: c.Bool("verbose"),
|
||||||
|
CodeSignCmd: c.String("codesign"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := c.StringSlice("entitlements"); len(v) > 0 {
|
||||||
|
e := sign.Entitlements(v)
|
||||||
|
signOpts.Entitlements = &e
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.quiet {
|
||||||
|
signOpts.Output = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
return sign.Files(c.Context, c.Args().Slice(), signOpts)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Commit struct {
|
type Commit struct {
|
||||||
SHA string `yaml:"sha"`
|
SHA string `yaml:"sha" json:"sha"`
|
||||||
Date *time.Time `yaml:"date"`
|
Date *time.Time `yaml:"date" json:"date"`
|
||||||
Author string `yaml:"author"`
|
Author string `yaml:"author" json:"author"`
|
||||||
Committer string `yaml:"committer"`
|
Committer string `yaml:"committer" json:"committer"`
|
||||||
Message string `yaml:"message"`
|
Message string `yaml:"message" json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(rc *github.RepositoryCommit) *Commit {
|
func New(rc *github.RepositoryCommit) *Commit {
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package osinfo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OSInfo struct {
|
type OSInfo struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name" json:"name"`
|
||||||
Version string `yaml:"version"`
|
Version string `yaml:"version" json:"version"`
|
||||||
Arch string `yaml:"arch"`
|
Arch string `yaml:"arch" json:"arch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() (*OSInfo, error) {
|
func New() (*OSInfo, error) {
|
||||||
@@ -29,8 +30,17 @@ func New() (*OSInfo, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OSInfo) MajorMinor() string {
|
// DistinctVersion returns macOS version down to a distinct "major"
|
||||||
|
// version. For macOS 10.x, this will include the first two numeric parts of the
|
||||||
|
// version (10.15), while for 11.x and later, the first numeric part is enough
|
||||||
|
// (11).
|
||||||
|
func (s *OSInfo) DistinctVersion() string {
|
||||||
parts := strings.Split(s.Version, ".")
|
parts := strings.Split(s.Version, ".")
|
||||||
|
|
||||||
|
if n, _ := strconv.Atoi(parts[0]); n >= 11 {
|
||||||
|
return parts[0]
|
||||||
|
}
|
||||||
|
|
||||||
max := len(parts)
|
max := len(parts)
|
||||||
if max > 2 {
|
if max > 2 {
|
||||||
max = 2
|
max = 2
|
||||||
|
|||||||
@@ -5,16 +5,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/commit"
|
"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/gh"
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/osinfo"
|
"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"
|
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/sanitize"
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
var nonAlphaNum = regexp.MustCompile(`[^\w_-]+`)
|
var gitTagMatcher = regexp.MustCompile(
|
||||||
|
`^emacs(-.*)?-((\d+\.\d+)(?:\.(\d+))?(-rc\d+)?(.+)?)$`,
|
||||||
|
)
|
||||||
|
|
||||||
type TestBuildType string
|
type TestBuildType string
|
||||||
|
|
||||||
@@ -35,7 +41,7 @@ type Options struct {
|
|||||||
Output io.Writer
|
Output io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
func Create(ctx context.Context, opts *Options) (*Plan, error) { //nolint:funlen
|
||||||
logger := hclog.FromContext(ctx).Named("plan")
|
logger := hclog.FromContext(ctx).Named("plan")
|
||||||
|
|
||||||
repo, err := repository.NewGitHub(opts.EmacsRepo)
|
repo, err := repository.NewGitHub(opts.EmacsRepo)
|
||||||
@@ -64,17 +70,36 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseName := fmt.Sprintf(
|
absoluteVersion := fmt.Sprintf(
|
||||||
"Emacs.%s.%s.%s",
|
"%s.%s.%s",
|
||||||
commitInfo.DateString(),
|
commitInfo.DateString(),
|
||||||
commitInfo.ShortSHA(),
|
commitInfo.ShortSHA(),
|
||||||
sanitizeString(opts.Ref),
|
sanitize.String(opts.Ref),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
version, channel, err := parseGitRef(opts.Ref)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var releaseName string
|
||||||
|
switch channel {
|
||||||
|
case release.Stable, release.RC:
|
||||||
|
releaseName = "Emacs-" + version
|
||||||
|
case release.Pretest:
|
||||||
|
version += "-pretest"
|
||||||
|
absoluteVersion += "-pretest"
|
||||||
|
releaseName = "Emacs-" + version
|
||||||
|
default:
|
||||||
|
version = absoluteVersion
|
||||||
|
releaseName = "Emacs." + version
|
||||||
|
}
|
||||||
|
|
||||||
buildName := fmt.Sprintf(
|
buildName := fmt.Sprintf(
|
||||||
"%s.%s.%s",
|
"Emacs.%s.%s.%s",
|
||||||
releaseName,
|
absoluteVersion,
|
||||||
sanitizeString(osInfo.Name+"-"+osInfo.MajorMinor()),
|
sanitize.String(osInfo.Name+"-"+osInfo.DistinctVersion()),
|
||||||
sanitizeString(osInfo.Arch),
|
sanitize.String(osInfo.Arch),
|
||||||
)
|
)
|
||||||
diskImage := buildName + ".dmg"
|
diskImage := buildName + ".dmg"
|
||||||
|
|
||||||
@@ -82,17 +107,19 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
|||||||
Build: &Build{
|
Build: &Build{
|
||||||
Name: buildName,
|
Name: buildName,
|
||||||
},
|
},
|
||||||
Source: &Source{
|
Source: &source.Source{
|
||||||
Ref: opts.Ref,
|
Ref: opts.Ref,
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
Commit: commitInfo,
|
Commit: commitInfo,
|
||||||
Tarball: &Tarball{
|
Tarball: &source.Tarball{
|
||||||
URL: repo.TarballURL(commitInfo.SHA),
|
URL: repo.TarballURL(commitInfo.SHA),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
OS: osInfo,
|
OS: osInfo,
|
||||||
Release: &Release{
|
Release: &Release{
|
||||||
Name: releaseName,
|
Name: releaseName,
|
||||||
|
Prerelease: channel != release.Stable,
|
||||||
|
Channel: channel,
|
||||||
},
|
},
|
||||||
Output: &Output{
|
Output: &Output{
|
||||||
Directory: opts.OutputDir,
|
Directory: opts.OutputDir,
|
||||||
@@ -101,15 +128,17 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.TestBuild != "" {
|
if opts.TestBuild != "" {
|
||||||
testName := sanitizeString(opts.TestBuild)
|
testName := sanitize.String(opts.TestBuild)
|
||||||
|
|
||||||
plan.Build.Name += ".test." + testName
|
plan.Build.Name += ".test." + testName
|
||||||
plan.Release.Title = "Test Builds"
|
plan.Release.Title = "Test Builds (" + testName + ")"
|
||||||
plan.Release.Name = "test-builds"
|
plan.Release.Name = "test-builds"
|
||||||
if opts.TestBuildType == Draft {
|
|
||||||
plan.Release.Draft = true
|
plan.Release.Prerelease = false
|
||||||
} else {
|
plan.Release.Draft = true
|
||||||
|
if opts.TestBuildType == Prerelease {
|
||||||
plan.Release.Prerelease = true
|
plan.Release.Prerelease = true
|
||||||
|
plan.Release.Draft = false
|
||||||
}
|
}
|
||||||
|
|
||||||
index := strings.LastIndex(diskImage, ".")
|
index := strings.LastIndex(diskImage, ".")
|
||||||
@@ -120,6 +149,35 @@ func Create(ctx context.Context, opts *Options) (*Plan, error) {
|
|||||||
return plan, nil
|
return plan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sanitizeString(s string) string {
|
func parseGitRef(ref string) (string, release.Channel, error) {
|
||||||
return nonAlphaNum.ReplaceAllString(s, "-")
|
m := gitTagMatcher.FindStringSubmatch(ref)
|
||||||
|
|
||||||
|
if len(m) == 0 {
|
||||||
|
return "", release.Nightly, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(m[1], "pretest") {
|
||||||
|
return m[2], release.Pretest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[4] != "" {
|
||||||
|
n, err := strconv.Atoi(m[4])
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n >= 90 {
|
||||||
|
return m[2], release.Pretest, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(m[5], "-rc") {
|
||||||
|
return m[2], release.RC, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m[2] == m[3] {
|
||||||
|
return m[2], release.Stable, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", "", nil
|
||||||
}
|
}
|
||||||
|
|||||||
421
pkg/plan/create_test.go
Normal file
421
pkg/plan/create_test.go
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/release"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parseGitRef(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
ref string
|
||||||
|
}
|
||||||
|
type want struct {
|
||||||
|
version string
|
||||||
|
channel release.Channel
|
||||||
|
err string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want want
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "master",
|
||||||
|
args: args{ref: "master"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-28",
|
||||||
|
args: args{ref: "emacs-28"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27",
|
||||||
|
args: args{ref: "emacs-27"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26",
|
||||||
|
args: args{ref: "emacs-26"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24",
|
||||||
|
args: args{ref: "emacs-24"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "feature/native-comp",
|
||||||
|
args: args{ref: "feature/native-comp"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "feature/pgtk",
|
||||||
|
args: args{ref: "feature/pgtk"},
|
||||||
|
want: want{version: "", channel: release.Nightly, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-19.34",
|
||||||
|
args: args{ref: "emacs-19.34"},
|
||||||
|
want: want{version: "19.34", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-20.4",
|
||||||
|
args: args{ref: "emacs-20.4"},
|
||||||
|
want: want{version: "20.4", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-22.3",
|
||||||
|
args: args{ref: "emacs-22.3"},
|
||||||
|
want: want{version: "22.3", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-23.4",
|
||||||
|
args: args{ref: "emacs-23.4"},
|
||||||
|
want: want{version: "23.4", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.0.97",
|
||||||
|
args: args{ref: "emacs-24.0.97"},
|
||||||
|
want: want{version: "24.0.97", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.2",
|
||||||
|
args: args{ref: "emacs-24.2"},
|
||||||
|
want: want{version: "24.2", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.2.90",
|
||||||
|
args: args{ref: "emacs-24.2.90"},
|
||||||
|
want: want{version: "24.2.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.2.93",
|
||||||
|
args: args{ref: "emacs-24.2.93"},
|
||||||
|
want: want{version: "24.2.93", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.3",
|
||||||
|
args: args{ref: "emacs-24.3"},
|
||||||
|
want: want{version: "24.3", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.3-rc1",
|
||||||
|
args: args{ref: "emacs-24.3-rc1"},
|
||||||
|
want: want{version: "24.3-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.3.90",
|
||||||
|
args: args{ref: "emacs-24.3.90"},
|
||||||
|
want: want{version: "24.3.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.3.94",
|
||||||
|
args: args{ref: "emacs-24.3.94"},
|
||||||
|
want: want{version: "24.3.94", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.4",
|
||||||
|
args: args{ref: "emacs-24.4"},
|
||||||
|
want: want{version: "24.4", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.4-rc1",
|
||||||
|
args: args{ref: "emacs-24.4-rc1"},
|
||||||
|
want: want{version: "24.4-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.4.90",
|
||||||
|
args: args{ref: "emacs-24.4.90"},
|
||||||
|
want: want{version: "24.4.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.4.91",
|
||||||
|
args: args{ref: "emacs-24.4.91"},
|
||||||
|
want: want{version: "24.4.91", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.5",
|
||||||
|
args: args{ref: "emacs-24.5"},
|
||||||
|
want: want{version: "24.5", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.5-rc1",
|
||||||
|
args: args{ref: "emacs-24.5-rc1"},
|
||||||
|
want: want{version: "24.5-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.5-rc3",
|
||||||
|
args: args{ref: "emacs-24.5-rc3"},
|
||||||
|
want: want{version: "24.5-rc3", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-24.5-rc3-fixed",
|
||||||
|
args: args{ref: "emacs-24.5-rc3-fixed"},
|
||||||
|
want: want{version: "24.5-rc3-fixed", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.0.90",
|
||||||
|
args: args{ref: "emacs-25.0.90"},
|
||||||
|
want: want{version: "25.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.0.95",
|
||||||
|
args: args{ref: "emacs-25.0.95"},
|
||||||
|
want: want{version: "25.0.95", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.1",
|
||||||
|
args: args{ref: "emacs-25.1"},
|
||||||
|
want: want{version: "25.1", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.1-rc1",
|
||||||
|
args: args{ref: "emacs-25.1-rc1"},
|
||||||
|
want: want{version: "25.1-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.1-rc2",
|
||||||
|
args: args{ref: "emacs-25.1-rc2"},
|
||||||
|
want: want{version: "25.1-rc2", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.1.90",
|
||||||
|
args: args{ref: "emacs-25.1.90"},
|
||||||
|
want: want{version: "25.1.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.1.91",
|
||||||
|
args: args{ref: "emacs-25.1.91"},
|
||||||
|
want: want{version: "25.1.91", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.2",
|
||||||
|
args: args{ref: "emacs-25.2"},
|
||||||
|
want: want{version: "25.2", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.2-rc1",
|
||||||
|
args: args{ref: "emacs-25.2-rc1"},
|
||||||
|
want: want{version: "25.2-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-25.2-rc2",
|
||||||
|
args: args{ref: "emacs-25.2-rc2"},
|
||||||
|
want: want{version: "25.2-rc2", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.0.90",
|
||||||
|
args: args{ref: "emacs-26.0.90"},
|
||||||
|
want: want{version: "26.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.0.91",
|
||||||
|
args: args{ref: "emacs-26.0.91"},
|
||||||
|
want: want{version: "26.0.91", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.1",
|
||||||
|
args: args{ref: "emacs-26.1"},
|
||||||
|
want: want{version: "26.1", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.1-rc1",
|
||||||
|
args: args{ref: "emacs-26.1-rc1"},
|
||||||
|
want: want{version: "26.1-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.1.90",
|
||||||
|
args: args{ref: "emacs-26.1.90"},
|
||||||
|
want: want{version: "26.1.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.1.92",
|
||||||
|
args: args{ref: "emacs-26.1.92"},
|
||||||
|
want: want{version: "26.1.92", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.2",
|
||||||
|
args: args{ref: "emacs-26.2"},
|
||||||
|
want: want{version: "26.2", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.2.90",
|
||||||
|
args: args{ref: "emacs-26.2.90"},
|
||||||
|
want: want{version: "26.2.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.3",
|
||||||
|
args: args{ref: "emacs-26.3"},
|
||||||
|
want: want{version: "26.3", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-26.3-rc1",
|
||||||
|
args: args{ref: "emacs-26.3-rc1"},
|
||||||
|
want: want{version: "26.3-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.0.90",
|
||||||
|
args: args{ref: "emacs-27.0.90"},
|
||||||
|
want: want{version: "27.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.0.91",
|
||||||
|
args: args{ref: "emacs-27.0.91"},
|
||||||
|
want: want{version: "27.0.91", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.1",
|
||||||
|
args: args{ref: "emacs-27.1"},
|
||||||
|
want: want{version: "27.1", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.1-rc1",
|
||||||
|
args: args{ref: "emacs-27.1-rc1"},
|
||||||
|
want: want{version: "27.1-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.1-rc2",
|
||||||
|
args: args{ref: "emacs-27.1-rc2"},
|
||||||
|
want: want{version: "27.1-rc2", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.1.90",
|
||||||
|
args: args{ref: "emacs-27.1.90"},
|
||||||
|
want: want{version: "27.1.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.1.91",
|
||||||
|
args: args{ref: "emacs-27.1.91"},
|
||||||
|
want: want{version: "27.1.91", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.2",
|
||||||
|
args: args{ref: "emacs-27.2"},
|
||||||
|
want: want{version: "27.2", channel: release.Stable, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.2-rc1",
|
||||||
|
args: args{ref: "emacs-27.2-rc1"},
|
||||||
|
want: want{version: "27.2-rc1", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-27.2-rc2",
|
||||||
|
args: args{ref: "emacs-27.2-rc2"},
|
||||||
|
want: want{version: "27.2-rc2", channel: release.RC, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-28.0.90",
|
||||||
|
args: args{ref: "emacs-28.0.90"},
|
||||||
|
want: want{version: "28.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-21.0.100",
|
||||||
|
args: args{ref: "emacs-pretest-21.0.100"},
|
||||||
|
want: want{version: "21.0.100", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-21.0.106",
|
||||||
|
args: args{ref: "emacs-pretest-21.0.106"},
|
||||||
|
want: want{version: "21.0.106", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-21.0.90",
|
||||||
|
args: args{ref: "emacs-pretest-21.0.90"},
|
||||||
|
want: want{version: "21.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-21.0.99",
|
||||||
|
args: args{ref: "emacs-pretest-21.0.99"},
|
||||||
|
want: want{version: "21.0.99", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-22.0.90",
|
||||||
|
args: args{ref: "emacs-pretest-22.0.90"},
|
||||||
|
want: want{version: "22.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-22.0.99",
|
||||||
|
args: args{ref: "emacs-pretest-22.0.99"},
|
||||||
|
want: want{version: "22.0.99", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-22.0.990",
|
||||||
|
args: args{ref: "emacs-pretest-22.0.990"},
|
||||||
|
want: want{version: "22.0.990", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-22.1.90",
|
||||||
|
args: args{ref: "emacs-pretest-22.1.90"},
|
||||||
|
want: want{version: "22.1.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-22.2.90",
|
||||||
|
args: args{ref: "emacs-pretest-22.2.90"},
|
||||||
|
want: want{version: "22.2.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.0.90",
|
||||||
|
args: args{ref: "emacs-pretest-23.0.90"},
|
||||||
|
want: want{version: "23.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.1.90",
|
||||||
|
args: args{ref: "emacs-pretest-23.1.90"},
|
||||||
|
want: want{version: "23.1.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.2.90",
|
||||||
|
args: args{ref: "emacs-pretest-23.2.90"},
|
||||||
|
want: want{version: "23.2.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.2.91",
|
||||||
|
args: args{ref: "emacs-pretest-23.2.91"},
|
||||||
|
want: want{version: "23.2.91", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.2.93",
|
||||||
|
args: args{ref: "emacs-pretest-23.2.93"},
|
||||||
|
want: want{version: "23.2.93", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.2.93.1",
|
||||||
|
args: args{ref: "emacs-pretest-23.2.93.1"},
|
||||||
|
want: want{version: "23.2.93.1", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-23.3.90",
|
||||||
|
args: args{ref: "emacs-pretest-23.3.90"},
|
||||||
|
want: want{version: "23.3.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-24.0.05",
|
||||||
|
args: args{ref: "emacs-pretest-24.0.05"},
|
||||||
|
want: want{version: "24.0.05", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emacs-pretest-24.0.90",
|
||||||
|
args: args{ref: "emacs-pretest-24.0.90"},
|
||||||
|
want: want{version: "24.0.90", channel: release.Pretest, err: ""},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, gotChannel, err := parseGitRef(tt.args.ref)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want.version, got)
|
||||||
|
assert.Equal(t, tt.want.channel, gotChannel)
|
||||||
|
|
||||||
|
if tt.want.err == "" {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
assert.EqualError(t, err, tt.want.err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,21 +2,22 @@ package plan
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/commit"
|
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/osinfo"
|
"github.com/jimeh/build-emacs-for-macos/pkg/osinfo"
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
|
"github.com/jimeh/build-emacs-for-macos/pkg/release"
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/source"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Plan struct {
|
type Plan struct {
|
||||||
Build *Build `yaml:"build,omitempty"`
|
Build *Build `yaml:"build,omitempty" json:"build,omitempty"`
|
||||||
Source *Source `yaml:"source,omitempty"`
|
Source *source.Source `yaml:"source,omitempty" json:"source,omitempty"`
|
||||||
OS *osinfo.OSInfo `yaml:"os,omitempty"`
|
OS *osinfo.OSInfo `yaml:"os,omitempty" json:"os,omitempty"`
|
||||||
Release *Release `yaml:"release,omitempty"`
|
Release *Release `yaml:"release,omitempty" json:"release,omitempty"`
|
||||||
Output *Output `yaml:"output,omitempty"`
|
Output *Output `yaml:"output,omitempty" json:"output,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load attempts to loads a plan YAML from given filename.
|
// Load attempts to loads a plan YAML from given filename.
|
||||||
@@ -54,29 +55,38 @@ func (s *Plan) YAML() (string, error) {
|
|||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteJSON writes plan in JSON format to given io.Writer.
|
||||||
|
func (s *Plan) WriteJSON(w io.Writer) error {
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
|
||||||
|
return enc.Encode(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON returns plan in JSON format.
|
||||||
|
func (s *Plan) JSON() (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := s.WriteJSON(&buf)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
type Build struct {
|
type Build struct {
|
||||||
Name string `yaml:"name,omitempty"`
|
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
type Source struct {
|
|
||||||
Ref string `yaml:"ref,omitempty"`
|
|
||||||
Repository *repository.Repository `yaml:"repository,omitempty"`
|
|
||||||
Commit *commit.Commit `yaml:"commit,omitempty"`
|
|
||||||
Tarball *Tarball `yaml:"tarball,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tarball struct {
|
|
||||||
URL string `yaml:"url,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Release struct {
|
type Release struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name" json:"name"`
|
||||||
Title string `yaml:"title,omitempty"`
|
Title string `yaml:"title,omitempty" json:"title,omitempty"`
|
||||||
Draft bool `yaml:"draft,omitempty"`
|
Draft bool `yaml:"draft,omitempty" json:"draft,omitempty"`
|
||||||
Prerelease bool `yaml:"prerelease,omitempty"`
|
Prerelease bool `yaml:"prerelease,omitempty" json:"prerelease,omitempty"`
|
||||||
|
Channel release.Channel `yaml:"channel,omitempty" json:"channel,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Output struct {
|
type Output struct {
|
||||||
Directory string `yaml:"directory,omitempty"`
|
Directory string `yaml:"directory,omitempty" json:"directory,omitempty"`
|
||||||
DiskImage string `yaml:"disk_image,omitempty"`
|
DiskImage string `yaml:"disk_image,omitempty" json:"disk_image,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
84
pkg/release/bulk.go
Normal file
84
pkg/release/bulk.go
Normal 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
|
||||||
|
}
|
||||||
11
pkg/release/channel.go
Normal file
11
pkg/release/channel.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package release
|
||||||
|
|
||||||
|
type Channel string
|
||||||
|
|
||||||
|
// Release channels
|
||||||
|
const (
|
||||||
|
Stable Channel = "stable"
|
||||||
|
RC Channel = "release-candidate"
|
||||||
|
Pretest Channel = "pretest"
|
||||||
|
Nightly Channel = "nightly"
|
||||||
|
)
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/gh"
|
"github.com/jimeh/build-emacs-for-macos/pkg/gh"
|
||||||
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
|
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
type releaseType int
|
type releaseType int
|
||||||
@@ -40,15 +41,26 @@ type PublishOptions struct {
|
|||||||
// draft)
|
// draft)
|
||||||
ReleaseType releaseType
|
ReleaseType releaseType
|
||||||
|
|
||||||
|
// Source contains the source used to build the asset files. When set a
|
||||||
|
// release body/description text will be generated based on source commit
|
||||||
|
// details.
|
||||||
|
Source *source.Source
|
||||||
|
|
||||||
// AssetFiles is a list of files which must all exist in the release for
|
// AssetFiles is a list of files which must all exist in the release for
|
||||||
// the check to pass.
|
// the check to pass.
|
||||||
AssetFiles []string
|
AssetFiles []string
|
||||||
|
|
||||||
|
// AssetSizeCheck causes a file size check for any existing asset files on a
|
||||||
|
// release which have the same filename as a asset we want to upload. If the
|
||||||
|
// size of the local and remote files are the same, the existing asset file
|
||||||
|
// is left in place. When this is false, given asset files will always be
|
||||||
|
// uploaded, replacing any asset files with the same filename.
|
||||||
|
AssetSizeCheck bool
|
||||||
|
|
||||||
// GitHubToken is the OAuth token used to talk to the GitHub API.
|
// GitHubToken is the OAuth token used to talk to the GitHub API.
|
||||||
GithubToken string
|
GithubToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:funlen,gocyclo
|
|
||||||
// Publish creates and publishes a GitHub release.
|
// Publish creates and publishes a GitHub release.
|
||||||
func Publish(ctx context.Context, opts *PublishOptions) error {
|
func Publish(ctx context.Context, opts *PublishOptions) error {
|
||||||
logger := hclog.FromContext(ctx).Named("release")
|
logger := hclog.FromContext(ctx).Named("release")
|
||||||
@@ -68,6 +80,16 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
prerelease := opts.ReleaseType == Prerelease
|
prerelease := opts.ReleaseType == Prerelease
|
||||||
draft := opts.ReleaseType == Draft
|
draft := opts.ReleaseType == Draft
|
||||||
|
|
||||||
|
body := ""
|
||||||
|
if opts.Source != nil {
|
||||||
|
body, err = releaseBody(opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("rendered release body", "content", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
created := false
|
||||||
logger.Info("checking release", "tag", tagName)
|
logger.Info("checking release", "tag", tagName)
|
||||||
release, resp, err := gh.Repositories.GetReleaseByTag(
|
release, resp, err := gh.Repositories.GetReleaseByTag(
|
||||||
ctx, opts.Repository.Owner(), opts.Repository.Name(), tagName,
|
ctx, opts.Repository.Owner(), opts.Repository.Name(), tagName,
|
||||||
@@ -77,6 +99,7 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
created = true
|
||||||
logger.Info("creating release", "tag", tagName, "name", name)
|
logger.Info("creating release", "tag", tagName, "name", name)
|
||||||
|
|
||||||
release, _, err = gh.Repositories.CreateRelease(
|
release, _, err = gh.Repositories.CreateRelease(
|
||||||
@@ -87,6 +110,7 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
TargetCommitish: &opts.CommitRef,
|
TargetCommitish: &opts.CommitRef,
|
||||||
Prerelease: boolPtr(false),
|
Prerelease: boolPtr(false),
|
||||||
Draft: boolPtr(true),
|
Draft: boolPtr(true),
|
||||||
|
Body: &body,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -94,62 +118,9 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fileName := range files {
|
err = uploadReleaseAssets(ctx, gh, release, files, opts)
|
||||||
fileIO, err2 := os.Open(fileName)
|
if err != nil {
|
||||||
if err2 != nil {
|
return err
|
||||||
return err2
|
|
||||||
}
|
|
||||||
defer fileIO.Close()
|
|
||||||
|
|
||||||
fileInfo, err2 := fileIO.Stat()
|
|
||||||
if err2 != nil {
|
|
||||||
return err2
|
|
||||||
}
|
|
||||||
|
|
||||||
fileBaseName := filepath.Base(fileName)
|
|
||||||
assetExists := false
|
|
||||||
|
|
||||||
for _, a := range release.Assets {
|
|
||||||
if a.GetName() != fileBaseName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.GetSize() == int(fileInfo.Size()) {
|
|
||||||
logger.Info("asset exists with correct size",
|
|
||||||
"file", fileBaseName,
|
|
||||||
"local_size", byteCountIEC(fileInfo.Size()),
|
|
||||||
"remote_size", byteCountIEC(int64(a.GetSize())),
|
|
||||||
)
|
|
||||||
assetExists = true
|
|
||||||
} else {
|
|
||||||
_, err = gh.Repositories.DeleteReleaseAsset(
|
|
||||||
ctx, opts.Repository.Owner(), opts.Repository.Name(),
|
|
||||||
a.GetID(),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Info(
|
|
||||||
"deleted asset with wrong size", "file", fileBaseName,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !assetExists {
|
|
||||||
logger.Info("uploading asset",
|
|
||||||
"file", fileBaseName,
|
|
||||||
"size", byteCountIEC(fileInfo.Size()),
|
|
||||||
)
|
|
||||||
_, _, err2 = gh.Repositories.UploadReleaseAsset(
|
|
||||||
ctx, opts.Repository.Owner(), opts.Repository.Name(),
|
|
||||||
release.GetID(),
|
|
||||||
&github.UploadOptions{Name: fileBaseName},
|
|
||||||
fileIO,
|
|
||||||
)
|
|
||||||
if err2 != nil {
|
|
||||||
return err2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changed := false
|
changed := false
|
||||||
@@ -158,6 +129,11 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if body != "" && release.GetBody() != body {
|
||||||
|
release.Body = &body
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
if release.GetDraft() != draft {
|
if release.GetDraft() != draft {
|
||||||
release.Draft = &draft
|
release.Draft = &draft
|
||||||
changed = true
|
changed = true
|
||||||
@@ -169,6 +145,7 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
|
logger.Info("updating release attributes", "url", release.GetHTMLURL())
|
||||||
release, _, err = gh.Repositories.EditRelease(
|
release, _, err = gh.Repositories.EditRelease(
|
||||||
ctx, opts.Repository.Owner(), opts.Repository.Name(),
|
ctx, opts.Repository.Owner(), opts.Repository.Name(),
|
||||||
release.GetID(), release,
|
release.GetID(), release,
|
||||||
@@ -178,13 +155,89 @@ func Publish(ctx context.Context, opts *PublishOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("release created", "url", release.GetHTMLURL())
|
if created {
|
||||||
|
logger.Info("release created", "url", release.GetHTMLURL())
|
||||||
|
} else {
|
||||||
|
logger.Info("release updated", "url", release.GetHTMLURL())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func uploadReleaseAssets(
|
||||||
|
ctx context.Context,
|
||||||
|
gh *github.Client,
|
||||||
|
release *github.RepositoryRelease,
|
||||||
|
fileNames []string,
|
||||||
|
opts *PublishOptions,
|
||||||
|
) error {
|
||||||
|
logger := hclog.FromContext(ctx).Named("release")
|
||||||
|
|
||||||
|
for _, fileName := range fileNames {
|
||||||
|
logger.Debug("processing asset", "file", filepath.Base(fileName))
|
||||||
|
|
||||||
|
fileIO, err := os.Open(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fileIO.Close()
|
||||||
|
|
||||||
|
fileInfo, err := fileIO.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileBaseName := filepath.Base(fileName)
|
||||||
|
assetExists := false
|
||||||
|
|
||||||
|
for _, a := range release.Assets {
|
||||||
|
if a.GetName() != fileBaseName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.AssetSizeCheck && a.GetSize() == int(fileInfo.Size()) {
|
||||||
|
logger.Info("asset exists with correct size",
|
||||||
|
"file", fileBaseName,
|
||||||
|
"local_size", byteCountIEC(fileInfo.Size()),
|
||||||
|
"remote_size", byteCountIEC(int64(a.GetSize())),
|
||||||
|
)
|
||||||
|
assetExists = true
|
||||||
|
} else {
|
||||||
|
logger.Info(
|
||||||
|
"deleting existing asset", "file", fileBaseName,
|
||||||
|
)
|
||||||
|
_, err = gh.Repositories.DeleteReleaseAsset(
|
||||||
|
ctx, opts.Repository.Owner(), opts.Repository.Name(),
|
||||||
|
a.GetID(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assetExists {
|
||||||
|
logger.Info("uploading asset",
|
||||||
|
"file", fileBaseName,
|
||||||
|
"size", byteCountIEC(fileInfo.Size()),
|
||||||
|
)
|
||||||
|
_, _, err = gh.Repositories.UploadReleaseAsset(
|
||||||
|
ctx, opts.Repository.Owner(), opts.Repository.Name(),
|
||||||
|
release.GetID(),
|
||||||
|
&github.UploadOptions{Name: fileBaseName},
|
||||||
|
fileIO,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func publishFileList(files []string) ([]string, error) {
|
func publishFileList(files []string) ([]string, error) {
|
||||||
var output []string
|
results := map[string]struct{}{}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
var err error
|
var err error
|
||||||
file, err = filepath.Abs(file)
|
file, err = filepath.Abs(file)
|
||||||
@@ -200,11 +253,10 @@ func publishFileList(files []string) ([]string, error) {
|
|||||||
return nil, fmt.Errorf("\"%s\" is not a file", file)
|
return nil, fmt.Errorf("\"%s\" is not a file", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
output = append(output, file)
|
results[file] = struct{}{}
|
||||||
sumFile := file + ".sha256"
|
sumFile := file + ".sha256"
|
||||||
|
|
||||||
_, err = os.Stat(sumFile)
|
_, err = os.Stat(sumFile)
|
||||||
fmt.Printf("err: %+v\n", err)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
@@ -212,7 +264,12 @@ func publishFileList(files []string) ([]string, error) {
|
|||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
output = append(output, sumFile)
|
results[sumFile] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var output []string
|
||||||
|
for f := range results {
|
||||||
|
output = append(output, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
return output, nil
|
return output, nil
|
||||||
|
|||||||
78
pkg/release/release_body.go
Normal file
78
pkg/release/release_body.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package release
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tplFuncs = template.FuncMap{
|
||||||
|
"indent": func(n int, s string) string {
|
||||||
|
pad := strings.Repeat(" ", n)
|
||||||
|
|
||||||
|
return pad + strings.ReplaceAll(s, "\n", "\n"+pad)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var bodyTpl = template.Must(template.New("body").Funcs(tplFuncs).Parse(`
|
||||||
|
{{- $t := "` + "`" + `" -}}
|
||||||
|
### Build Details
|
||||||
|
|
||||||
|
{{ with .SourceURL -}}
|
||||||
|
- Source: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .CommitURL }}
|
||||||
|
- Commit: {{ .CommitURL }}
|
||||||
|
{{- if .CommitSHA }} ({{ $t }}{{ .CommitSHA }}{{ $t }}){{ end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .TarballURL }}
|
||||||
|
- Tarball: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .BuildLogURL }}
|
||||||
|
- Build Log: {{ . }} (available for 90 days)
|
||||||
|
{{- end }}`,
|
||||||
|
))
|
||||||
|
|
||||||
|
type bodyData struct {
|
||||||
|
SourceURL string
|
||||||
|
CommitSHA string
|
||||||
|
CommitURL string
|
||||||
|
BuildLogURL string
|
||||||
|
TarballURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func releaseBody(opts *PublishOptions) (string, error) {
|
||||||
|
src := opts.Source
|
||||||
|
|
||||||
|
if src.Repository == nil || src.Commit == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &bodyData{
|
||||||
|
SourceURL: src.Repository.TreeURL(src.Ref),
|
||||||
|
CommitSHA: src.Commit.SHA,
|
||||||
|
CommitURL: src.Repository.CommitURL(src.Commit.SHA),
|
||||||
|
TarballURL: src.Repository.TarballURL(src.Commit.SHA),
|
||||||
|
}
|
||||||
|
|
||||||
|
// If available, use the exact value from the build plan.
|
||||||
|
if src.Tarball != nil {
|
||||||
|
data.TarballURL = src.Tarball.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// If running within GitHub Actions, provide link to build log.
|
||||||
|
if opts.Repository != nil {
|
||||||
|
if id := os.Getenv("GITHUB_RUN_ID"); id != "" {
|
||||||
|
data.BuildLogURL = opts.Repository.ActionRunURL(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := bodyTpl.Execute(&buf, data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
44
pkg/release/version.go
Normal file
44
pkg/release/version.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package release
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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]+)?$`)
|
||||||
|
stableGitRef = regexp.MustCompile(`^emacs-(\d+\.\d+(?:[a-z]+)?)$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func VersionToName(version string) (string, error) {
|
||||||
|
if version == "" {
|
||||||
|
return "", ErrEmptyVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
if stableVersion.MatchString(version) ||
|
||||||
|
strings.HasSuffix(version, "-pretest") {
|
||||||
|
return "Emacs-" + version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Emacs." + version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GitRefToStableVersion(ref string) (string, error) {
|
||||||
|
if m := stableGitRef.FindStringSubmatch(ref); len(m) > 1 {
|
||||||
|
return m[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("%w: \"%s\"", ErrNotStableRef, ref)
|
||||||
|
}
|
||||||
138
pkg/release/version_test.go
Normal file
138
pkg/release/version_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@ const GitHub Type = "github"
|
|||||||
// Repository represents basic information about a repository with helper
|
// Repository represents basic information about a repository with helper
|
||||||
// methods to get various pieces of information from it.
|
// methods to get various pieces of information from it.
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
Type Type `yaml:"type,omitempty"`
|
Type Type `yaml:"type,omitempty" json:"type,omitempty"`
|
||||||
Source string `yaml:"source,omitempty"`
|
Source string `yaml:"source,omitempty" json:"source,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGitHub(ownerAndName string) (*Repository, error) {
|
func NewGitHub(ownerAndName string) (*Repository, error) {
|
||||||
@@ -89,3 +89,54 @@ func (s *Repository) TarballURL(ref string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Repository) CommitURL(ref string) string {
|
||||||
|
if ref == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s.Type {
|
||||||
|
case GitHub:
|
||||||
|
return GitHubBaseURL + s.Source + "/commit/" + ref
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Repository) TreeURL(ref string) string {
|
||||||
|
if ref == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s.Type {
|
||||||
|
case GitHub:
|
||||||
|
return GitHubBaseURL + s.Source + "/tree/" + ref
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Repository) ActionRunURL(runID string) string {
|
||||||
|
if runID == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s.Type {
|
||||||
|
case GitHub:
|
||||||
|
return GitHubBaseURL + s.Source + "/actions/runs/" + runID
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Repository) ReleaseURL(releaseName string) string {
|
||||||
|
if releaseName == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch s.Type {
|
||||||
|
case GitHub:
|
||||||
|
return GitHubBaseURL + s.Source + "/releases/tag/" + releaseName
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
54
pkg/repository/repository_test.go
Normal file
54
pkg/repository/repository_test.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRepository_ReleaseURL(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
Type Type
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
releaseName string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty name",
|
||||||
|
fields: fields{Type: GitHub, Source: "foo/bar"},
|
||||||
|
args: args{releaseName: ""},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GitHub, foo/bar, v1.0.0",
|
||||||
|
fields: fields{Type: GitHub, Source: "foo/bar"},
|
||||||
|
args: args{releaseName: "v1.0.0"},
|
||||||
|
want: "https://github.com/foo/bar/releases/tag/v1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Not GitHub, foo/bar, v1.0.0",
|
||||||
|
fields: fields{Type: Type("oops"), Source: "foo/bar"},
|
||||||
|
args: args{releaseName: "v1.0.0"},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
repo := &Repository{
|
||||||
|
Type: tt.fields.Type,
|
||||||
|
Source: tt.fields.Source,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := repo.ReleaseURL(tt.args.releaseName)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
9
pkg/sanitize/string.go
Normal file
9
pkg/sanitize/string.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package sanitize
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
var nonAlphaNum = regexp.MustCompile(`[^\w_-]+`)
|
||||||
|
|
||||||
|
func String(s string) string {
|
||||||
|
return nonAlphaNum.ReplaceAllString(s, "-")
|
||||||
|
}
|
||||||
@@ -117,42 +117,24 @@ func signCLIHelper(ctx context.Context, appBundle string, opts *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// elnFiles finds all native-compilation *.eln files within a Emacs.app bundle,
|
// elnFiles finds all native-compilation *.eln files within a Emacs.app bundle,
|
||||||
// based on expected paths they might be stored in.
|
// excluding any *.eln which should be automatically located by codesign when
|
||||||
|
// signing the Emacs.app bundle itself with the --deep flag. Essentially this
|
||||||
|
// only returns *.eln files which must be individually signed before signing the
|
||||||
|
// app bundle itself.
|
||||||
func elnFiles(emacsApp string) ([]string, error) {
|
func elnFiles(emacsApp string) ([]string, error) {
|
||||||
dirs := []string{
|
|
||||||
// Current *.eln location.
|
|
||||||
filepath.Join(emacsApp, "Contents", "Resources", "native-lisp"),
|
|
||||||
// Legacy *.eln location.
|
|
||||||
filepath.Join(emacsApp, "Contents", "MacOS", "lib", "emacs"),
|
|
||||||
}
|
|
||||||
|
|
||||||
var files []string
|
var files []string
|
||||||
walkDirFunc := func(path string, _d fs.DirEntry, _err error) error {
|
walkDirFunc := func(path string, d fs.DirEntry, _err error) error {
|
||||||
if strings.HasSuffix(path, ".eln") {
|
if d.Type().IsRegular() && strings.HasSuffix(path, ".eln") &&
|
||||||
|
!strings.Contains(path, ".app/Contents/Frameworks/") {
|
||||||
files = append(files, path)
|
files = append(files, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range dirs {
|
err := filepath.WalkDir(filepath.Join(emacsApp, "Contents"), walkDirFunc)
|
||||||
fi, err := os.Stat(dir)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
if os.IsNotExist(err) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !fi.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = filepath.WalkDir(dir, walkDirFunc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return files, nil
|
return files, nil
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ var DefaultEmacsEntitlements = []string{
|
|||||||
"com.apple.security.cs.allow-jit",
|
"com.apple.security.cs.allow-jit",
|
||||||
"com.apple.security.network.client",
|
"com.apple.security.network.client",
|
||||||
"com.apple.security.cs.disable-library-validation",
|
"com.apple.security.cs.disable-library-validation",
|
||||||
|
"com.apple.security.cs.allow-dyld-environment-variables",
|
||||||
"com.apple.security.automation.apple-events",
|
"com.apple.security.automation.apple-events",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ var entitlementsTestCases = []struct {
|
|||||||
"com.apple.security.cs.allow-jit",
|
"com.apple.security.cs.allow-jit",
|
||||||
"com.apple.security.network.client",
|
"com.apple.security.network.client",
|
||||||
"com.apple.security.cs.disable-library-validation",
|
"com.apple.security.cs.disable-library-validation",
|
||||||
|
"com.apple.security.cs.allow-dyld-environment-variables",
|
||||||
"com.apple.security.automation.apple-events",
|
"com.apple.security.automation.apple-events",
|
||||||
},
|
},
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
@@ -64,6 +65,8 @@ var entitlementsTestCases = []struct {
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.cs.disable-library-validation</key>
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.security.automation.apple-events</key>
|
<key>com.apple.security.automation.apple-events</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -78,6 +81,7 @@ func TestDefaultEmacsEntitlements(t *testing.T) {
|
|||||||
"com.apple.security.cs.allow-jit",
|
"com.apple.security.cs.allow-jit",
|
||||||
"com.apple.security.network.client",
|
"com.apple.security.network.client",
|
||||||
"com.apple.security.cs.disable-library-validation",
|
"com.apple.security.cs.disable-library-validation",
|
||||||
|
"com.apple.security.cs.allow-dyld-environment-variables",
|
||||||
"com.apple.security.automation.apple-events",
|
"com.apple.security.automation.apple-events",
|
||||||
},
|
},
|
||||||
DefaultEmacsEntitlements,
|
DefaultEmacsEntitlements,
|
||||||
|
|||||||
17
pkg/source/source.go
Normal file
17
pkg/source/source.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package source
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/commit"
|
||||||
|
"github.com/jimeh/build-emacs-for-macos/pkg/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Source struct {
|
||||||
|
Ref string `yaml:"ref,omitempty" json:"ref,omitempty"`
|
||||||
|
Repository *repository.Repository `yaml:"repository,omitempty" json:"repository,omitempty"`
|
||||||
|
Commit *commit.Commit `yaml:"commit,omitempty" json:"commit,omitempty"`
|
||||||
|
Tarball *Tarball `yaml:"tarball,omitempty" json:"tarball,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tarball struct {
|
||||||
|
URL string `yaml:"url,omitempty" json:"url,omitempty"`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user