Skip to content

Commit bb56708

Browse files
authored
ci: publish: Move to release tag triggered publishing (#611)
* Move to release tag triggered publishing I still prefer my old GitHub UI triggered release. It feels much less complicated to me. But this project is part of clj-commons, and here I defer to the larger team's preference for release triggered publishing. I brought over this work from other projects, mostly rewrite-clj and pomegranate. These incude: - using neil to track/bump/store version in deps.edn - automatically including date in changelog release headers One refinement for Etaoin is avoiding the duplicate test run on Publish. The release tag triggered strategy includes a commit and tag from the person doing the publish. This commit triggers the normal Test workflow but the Publish workflow also triggers the Test workflow to ensure all is good before releasing. To avoid the duplicate test run, I've added a new `check-for-skip` job in the Test workflow to skip tests when appropriate. I'd love to skip the independent Test workflow on Publish entirely, but don't think the GitHub Actions YAML magic to do so exists. Closes #529 * merge new check-for-skip job into setup job Since the check-for-skip work needs pretty much the same setup as the setup job, merge the two and avoid the extra job. * yaml syntax * fix yaml * [publish workflow] should cause tests to be skipped A wee sanity test * [publish workflow] debug commit msg * remove println debug On a PR the commit message is the merge commit. That's not important to me, I care about behaviour on master, the branch from which we publish.
1 parent e1bbaf6 commit bb56708

16 files changed

+596
-444
lines changed

.github/workflows/publish.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Publish
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v\d+.*'
7+
8+
jobs:
9+
test:
10+
uses: ./.github/workflows/test.yml
11+
12+
publish:
13+
environment: publish
14+
runs-on: ubuntu-latest
15+
needs: [test]
16+
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Restore Clojure deps from cache
22+
uses: actions/cache/restore@v4
23+
with:
24+
path: |
25+
~/.m2/repository
26+
~/.deps.clj
27+
~/.gitlibs
28+
enableCrossOsArchive: true
29+
key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }}
30+
restore-keys: cljdeps-
31+
32+
- name: Setup Java
33+
uses: actions/setup-java@v4
34+
with:
35+
distribution: 'temurin'
36+
java-version: '21'
37+
38+
- name: Install Clojure Tools
39+
uses: DeLaGuardo/[email protected]
40+
with:
41+
bb: 'latest'
42+
43+
- name: Deploy to clojars
44+
env:
45+
CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }}
46+
CLOJARS_PASSWORD: ${{ secrets.CLOJARS_PASSWORD }}
47+
run: bb -ci-clojars-deploy
48+
49+
- name: Create GitHub Release
50+
env:
51+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
run: bb -ci-github-create-release
53+
54+
- name: Inform Cljdoc
55+
run: bb -ci-cljdoc-request-build

.github/workflows/release.yml

Lines changed: 0 additions & 78 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Test
22

33
on:
4+
workflow_call: # for Publish
45
push:
56
branches:
67
- master
@@ -13,6 +14,7 @@ jobs:
1314
runs-on: ubuntu-latest
1415

1516
outputs:
17+
skip_tests: ${{ steps.check_for_skip.outputs.skip_tests }}
1618
tests: ${{ steps.set-tests.outputs.tests }}
1719

1820
steps:
@@ -44,14 +46,20 @@ jobs:
4446
- name: Bring down deps
4547
run: bb download-deps
4648

49+
- name: Check if Tests Should Run
50+
id: check_for_skip
51+
run: bb -ci-set-skip-tests
52+
4753
- id: set-tests
54+
if: steps.check_for_skip.outputs.skip_tests == 'false'
4855
name: Set test var for matrix
4956
# run test.clj directly instead of via bb task to avoid generic task output
5057
run: echo "tests=$(bb script/test_matrix.clj --format json)" >> $GITHUB_OUTPUT
5158

5259
build:
5360
needs: setup
5461
runs-on: ${{ matrix.os }}-latest
62+
if: needs.setup.outputs.skip_tests == 'false'
5563
strategy:
5664
fail-fast: false
5765
matrix:
@@ -129,7 +137,6 @@ jobs:
129137
mv ../../../.gitlibs ${USERPROFILE}
130138
shell: bash
131139

132-
133140
- name: Setup Java
134141
uses: actions/setup-java@v4
135142
with:

CHANGELOG.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ A release with an intentional breaking changes is marked with:
1111
* [breaking] you probably need to change your code
1212
* [minor breaking] you likely don't need to change your code
1313

14+
// DO NOT EDIT: the "Unreleased" section header is automatically updated by bb publish
15+
// bb publish will fail on any of:
16+
// - unreleased section not found,
17+
// - unreleased section empty
18+
// - optional attribute is not [breaking] or [minor breaking]
19+
// (adjust these in publish.clj as you see fit)
1420
== Unreleased
1521

1622
* {pr}552[#552]: Add support for wide characters to input fill functions

bb.edn

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
:sha "cf44c15f30ea3867227fa61ceb823e5e942c707f"}
77
dev.nubank/docopt {:mvn/version "0.6.1-fix7"}
88
org.babashka/http-server {:mvn/version "0.1.12"}
9-
wevre/natural-compare {:mvn/version "0.0.10"}}
9+
wevre/natural-compare {:mvn/version "0.0.10"}
10+
io.github.babashka/neil {:git/tag "v0.3.67" :git/sha "054ca51"}}
1011
:tasks
1112
{;; setup
1213
:requires ([babashka.classpath :as cp]
@@ -57,7 +58,7 @@
5758
:task (do
5859
;; timbre default logging level is debug, which generates a lot of http logging noise
5960
(timbre/set-level! :info)
60-
(exec 'build-shared/test))
61+
(exec 'test-shared/test))
6162
:org.babashka/cli {:coerce {:nses [:symbol]
6263
:patterns [:string]
6364
:vars [:symbol]}}}
@@ -110,5 +111,14 @@
110111
fake-driver {:doc "Fake driver to support testing"
111112
:task-decoration :none
112113
:task fake-driver/-main}
113-
ci-release {:doc "release tasks, use --help for args"
114-
:task ci-release/-main}}}
114+
115+
pubcheck {:task publish/pubcheck :doc "Run only publish checks (without publishing)"}
116+
publish {:task publish/-main :doc "Publish a release (for maintainers)"}
117+
;; let's not rely on a random version of neil
118+
neil {:task babashka.neil/-main :doc "Pinned version of babashka/neil (used in scripting)"}
119+
120+
;; hidden tasks, no need for folks to be trying these ci invoked tasks
121+
-ci-set-skip-tests {:task ci-publish/set-skip-tests :doc "used on ci to determine if tests need to be run"}
122+
-ci-clojars-deploy {:task ci-publish/clojars-deploy :doc "triggered on ci by release tag"}
123+
-ci-github-create-release {:task ci-publish/github-create-release :doc "triggered on ci by release tag"}
124+
-ci-cljdoc-request-build {:task ci-publish/cljdoc-request-build :doc "ask cljdoc to build docs for new release"}}}

build.clj

Lines changed: 23 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,24 @@
11
(ns build
2-
(:require [clojure.edn :as edn]
3-
[clojure.java.io :as io]
2+
(:require [build-shared]
3+
[clojure.edn :as edn]
44
[clojure.tools.build.api :as b]))
55

6-
(defn version-string []
7-
(let [{:keys [major minor release qualifier]} (-> "version.edn"
8-
slurp
9-
edn/read-string)]
10-
(format "%s.%s.%s%s"
11-
major minor release (if qualifier
12-
(str "-" qualifier)
13-
""))))
6+
(def version (build-shared/lib-version))
7+
(def lib (build-shared/lib-artifact-name))
148

15-
(def lib 'etaoin/etaoin)
16-
(def version (version-string)) ;; the expectations is some pre-processing has bumped the version when releasing
179
(def class-dir "target/classes")
1810
(def basis (b/create-basis {:project "deps.edn"}))
1911
(def jar-file (format "target/%s.jar" (name lib)))
20-
(def built-jar-version-file "target/built-jar-version.txt")
21-
22-
(defn clean [_]
23-
(b/delete {:path "target"}))
2412

2513
(defn jar
2614
"Build library jar file.
27-
Also writes built version to target/built-jar-version.txt for easy peasy pickup by any interested downstream operation.
28-
29-
We use the optional :version-suffix to optionally distinguish local installs from productin releases.
30-
For example, when installing for a cljdoc preview suffix is: cljdoc-preview."
31-
[{:keys [version-suffix] :as opts}]
32-
(let [version (if version-suffix
33-
(format "%s-%s" version version-suffix)
34-
version)]
15+
Supports `:version-override` for local testing, otherwise official version is used.
16+
For example, when previewing for cljdoc we use a the version with -cljdoc-preview suffix."
17+
[{:keys [version-override] :as opts}]
18+
(b/delete {:path class-dir})
19+
(b/delete {:path jar-file})
20+
(let [version (or version-override version)]
21+
(println "jarring version" version)
3522
(b/write-pom {:class-dir class-dir
3623
:lib lib
3724
:version version
@@ -53,37 +40,26 @@
5340
:target-dir class-dir})
5441
(b/jar {:class-dir class-dir
5542
:jar-file jar-file})
56-
(spit built-jar-version-file version)
57-
(assoc opts :built-jar-version version)))
58-
59-
(defn- built-version* []
60-
(when (not (.exists (io/file built-jar-version-file)))
61-
(throw (ex-info (str "Built jar version file not found: " built-jar-version-file) {})))
62-
(slurp built-jar-version-file))
63-
64-
(defn built-version
65-
;; NOTE: Used by release script and github workflow
66-
"Spit out version of jar built (with no trailing newline).
67-
A separate task because I don't know what build.tools might spit to stdout."
68-
[_]
69-
(print (built-version*))
70-
(flush))
43+
(assoc opts :built-version version)))
7144

72-
(defn install [opts]
73-
(clean opts)
74-
(let [{:keys [built-jar-version]} (jar opts)]
45+
(defn install
46+
"Install built jar to local maven repo, optionally specify `:version-override` for local testing."
47+
[opts]
48+
(let [{:keys [built-version]} (jar opts)]
49+
(println "installing version" built-version)
7550
(b/install {:class-dir class-dir
7651
:lib lib
77-
:version built-jar-version
52+
:version built-version
7853
:basis basis
7954
:jar-file jar-file})))
8055

81-
(defn deploy [opts]
56+
(defn deploy [_]
57+
(jar {})
58+
(println "deploy")
8259
((requiring-resolve 'deps-deploy.deps-deploy/deploy)
8360
{:installer :remote
8461
:artifact jar-file
85-
:pom-file (b/pom-path {:lib lib :class-dir class-dir})})
86-
opts)
62+
:pom-file (b/pom-path {:lib lib :class-dir class-dir})}))
8763

8864
(defn download-deps
8965
"Download all deps for all aliases"
@@ -92,8 +68,7 @@
9268
slurp
9369
edn/read-string
9470
:aliases
95-
keys
96-
sort)]
71+
keys)]
9772
;; one at a time because aliases with :replace-deps will... well... you know.
9873
(println "Bring down default deps")
9974
(b/create-basis {})

build/build_shared.clj

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
(ns build-shared
2-
(:refer-clojure :exclude [test])
32
(:require
4-
[cognitect.test-runner :as tr]))
3+
[clojure.edn :as edn]
4+
[clojure.string :as string]))
55

6-
;; private fn pasted from original sources
7-
(defn- do-test
8-
[{:keys [dirs nses patterns vars includes excludes]}]
9-
(let [adapted {:dir (when (seq dirs) (set dirs))
10-
:namespace (when (seq nses) (set nses))
11-
:namespace-regex (when (seq patterns) (map re-pattern patterns))
12-
:var (when (seq vars) (set vars))
13-
:include (when (seq includes) (set includes))
14-
:exclude (when (seq excludes) (set excludes))}]
15-
(tr/test adapted)))
6+
(defn- project-info []
7+
(-> (edn/read-string (slurp "deps.edn"))
8+
:aliases :neil :project))
169

10+
(def version-tag-prefix "v")
1711

18-
(defn test
19-
"Reimplement test to not throw but instead exit with 1 on error."
20-
[opts]
21-
(try
22-
(let [{:keys [fail error]} (do-test opts)]
23-
(System/exit (if (zero? (+ fail error)) 0 1)))
24-
(finally
25-
;; Only called if `test` raises an exception
26-
(shutdown-agents))))
12+
(defn lib-version []
13+
(-> (project-info) :version))
14+
15+
(defn lib-artifact-name []
16+
(-> (project-info) :name))
17+
18+
(defn lib-github-coords []
19+
(-> (project-info) :github-coords))
20+
21+
(defn version->tag [version]
22+
(str version-tag-prefix version))
23+
24+
(defn tag->version [ci-tag]
25+
(and (string/starts-with? ci-tag version-tag-prefix)
26+
(string/replace-first ci-tag version-tag-prefix "")))

0 commit comments

Comments
 (0)