Skip to content

Improve release automation.#466

Merged
samwagg merged 10 commits into
masterfrom
XDR-27079-new-to-contained-interval
Mar 18, 2026
Merged

Improve release automation.#466
samwagg merged 10 commits into
masterfrom
XDR-27079-new-to-contained-interval

Conversation

@samwagg

@samwagg samwagg commented May 27, 2025

Copy link
Copy Markdown
Contributor

Updated 2026-03-16 to reflect all changes made during the review process.

Made these changes in consultation with @frenchy64.

  • Read CTIM schema version from resources/ctim/version.txt via a ctim-version macro (supports both clj and cljs).
  • Add sync-schema-version lein alias to update resources/ctim/version.txt to match the lein project version.
  • Integrate sync-schema-version into :release-tasks so the version file stays in sync across version bumps.
  • Consolidate the "doc" lein alias to sync the schema version before generating documentation.
  • Add test to verify the lein project version and CTIM schema version are in sync.
  • Remove defunct script/release.sh and rewrite README release instructions.
  • Remove GHA schedule trigger, which causes the workflow to be suspended after 60 days of inactivity.

@samwagg samwagg changed the title Xdr 27079 new to contained interval Improve release automation. May 27, 2025
@samwagg samwagg force-pushed the XDR-27079-new-to-contained-interval branch from a4c8db8 to 805d813 Compare May 27, 2025 21:58
@frenchy64

Copy link
Copy Markdown
Contributor

version.edn needs to be named something more unique like resources/ctim/version.edn to avoid clashing with other (unknowable) libs on the classpath.

Comment thread src/ctim/change_schema_version.clj
Comment thread src/ctim/schemas/common.cljc Outdated
Comment thread project.clj Outdated
@samwagg samwagg requested a review from frenchy64 May 28, 2025 16:15
@samwagg

samwagg commented May 28, 2025

Copy link
Copy Markdown
Contributor Author

@frenchy64 Addressed all your comments. Thanks!

Comment thread src/ctim/schemas/common.cljc Outdated
#?(:clj [ctim.lib.generators :as gen])
[ctim.lib.predicates :as pred]
[ctim.schemas.vocabularies :as v]
#?(:clj [ctim.version :refer [ctim-version]])

@frenchy64 frenchy64 May 29, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might work as-is in cljs. https://clojurescript.org/guides/ns-forms#_implicit_refer

Try removing the reader conditionals. If not, maybe we need to bump our cljs version.

@samwagg samwagg May 29, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so this doesn't work either. I think I understand why both this and :include-macros true don't work now.

Why ':include-macros true' doesn't work
Given an ns defined in file bar.clj (note extension .clj)
Given a file foo.cljs(note extension .cljs) with the following content:

(ns foo (:require [bar :include-macros true]))

desugars to:

(ns foo (:require-macros [bar])
  (:require [bar]))

The presence of both :require and :require-macros causes the cljs compiler to look for both clj and cljs namespaces foo, but there's only the clojure one.

Why implicit refer doesn't work
IIUC, the implicit refer also only works for scenarios where there is both a clj and cljs ns (with the additional constraint that the cljs dependency ns declares :require-macros on the clj ns of the same name).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, given that the macro is defined in a plain clj ns and that we are working in a cljc file where both of the resulting clj and cljs namespaces depend on the same macro, it is necessary for the cljs ns to declare a dependency on the macro ns using only :require-macros. And the only way to achieve that (I think) is for the cljc file to have separate :clj and :cljs conditionals.

@samwagg samwagg May 29, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another possibility is doing it all in the same file:

(ns ctim.schemas.common
  #?(:cljs (:require-macros [ctim.schemas.common :refer [ctim-version]]))
  
...

#?(:clj
   (defmacro ctim-version
     "This is a macro to support cljs compile-time inlining of the version string
     from the JVM resource."
     []
     (slurp (io/resource "ctim/version.txt"))))

(def ctim-schema-version (ctim-version))

Which I actually don't hate. It looks a little convoluted. But I'm not sure its worse than the separate file solution. If anything it's just making the quirks easier to see.

@frenchy64 frenchy64 May 29, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant I think there's a way to avoid reader conditionals and :require-macros altogether.

i.e., instead of

(ns ctim.schemas.common
  #?(:cljs (:require-macros [ctim.version :refer [ctim-version]]))
  (:require [ctim.version :refer [ctim-version]]))

try

(ns ctim.schemas.common
  (:require [ctim.version :refer [ctim-version]]))

or

(ns ctim.schemas.common
  (:require [ctim.version :as cv]))

Failing all that, this might work:

(ns ctim.schemas.common
  (#?(:clj :require :cljs :require-macros) [ctim.version :refer [ctim-version]]))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had tried your first suggestion. That's what I'm calling "implicit refer" (term is from that clojurescript doc) in my message above.

Your second suggestion does work fine, let's do it. I didn't realize it would let you have multiple :requires.

(:require [clj-momo.lib.clj-time.coerce :refer [to-long]]
#?(:clj [clojure.java.io :as io])
[clojure.set :refer [map-invert]]
[clojure.string :as str]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove requires of clojure.java.io and clojure.string.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the state of things was at the time of this comment, but as it stands:

  • clojure.string is still imported because it's used.
  • clojure.java.io is removed.

Comment thread src/ctim/change_schema_version.clj
Comment thread project.clj
["vcs" "tag" "--no-sign"]
["deploy" "clojars"]
["change" "version" "leiningen.release/bump-version"]
["sync-schema-version"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we always want to update the docs when we bump versions, and vice-versa.

Please redefine the "doc" alias to do the equivalent of running ctim.change-schema-version/-main followed by ctim.document/-main.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread README.md Outdated
# Patch version releases (minor and major increments require a manual edit of version).
# Expect this task to modify project files and deploy to Clojars.
# See `release-tasks` in project.clj for details.
lein release

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already recommended a few lines down. Could you consolidate them and separate the instructions so it doesn't look like you should execute them blindly top-to-bottom? I'm often in a hurry when reading this section.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll work on this tomorrow morning when my brain is fresh. I think there is more to do here too, such as warn about the mistakes I made when doing my release 😃 .

@samwagg samwagg force-pushed the XDR-27079-new-to-contained-interval branch from ac2e12b to 84a901e Compare March 13, 2026 18:59
@samwagg samwagg requested a review from brookeswanson as a code owner March 13, 2026 18:59
samwagg and others added 2 commits March 13, 2026 14:04
- Simplify cljs macro require using reader conditional on :require/:require-macros
- Remove unused clojure.java.io require
- Consolidate "doc" alias to sync schema version and generate docs together
- Restructure README release instructions for clarity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix change_schema_version to write to resources/ctim/version.txt
- Sync version.txt to current project version (1.3.30-SNAPSHOT)
- Remove stale resources/version.txt
- Rewrite release docs: add pre-release steps, split recovery scenarios

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@frenchy64 frenchy64 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that the project.clj is the source of truth.

Comment thread src/ctim/version.clj
(ns ctim.version
(:require [clojure.java.io :as io]))

(defmacro ctim-version

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be me misunderstanding how cljs works, but I'm unclear why this needs to be a macro

@frenchy64 frenchy64 Mar 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial problem here was that you'd need to manually update (def ctim-schema-version "1.3.30") every release with the new version. If you forgot, the version was desynced from project.clj

We considered two main solutions.

  1. Have leiningen write the new version directly to this def on version change.
  2. Create a separate file with the version that we refer to.

This implements 2. The reason it needs to be a macro is that cljs doesn't implement io/resource or slurp, so we need get the version string via JVM Clojure. Macros are expanded in JVM Clojure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a minute since I wrote this, but I think what's happening is that clojurescript needs to read the resource that holds the version at compile time, and having it as a macro allows the code to be evaluated at compile time instead of runtime.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I recall correctly, @frenchy64 and I had a lot of back-and-forth about how to keep the CTIM library and schema versions in sync, only some of which seems to be captured in the PR comments. Several ideas were considered, and the one we ended up with involves this version file and the need for the clj/cljs code to read from it to get the schema version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I hadn't seen @frenchy64's comment. He explains it better.

@samwagg samwagg merged commit 08551ef into master Mar 18, 2026
3 checks passed
@samwagg samwagg deleted the XDR-27079-new-to-contained-interval branch March 18, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants