@invarn/cibuild 2.8.8 → 2.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,11 +70,24 @@ fi`);
70
70
  executable(join(bin, 'bundle'), `echo "bundle $* (GEM_HOME=$GEM_HOME)" >> '${log}'`);
71
71
  executable(join(bin, 'pod'), `echo "pod $*" >> '${log}'`);
72
72
  executable(join(bin, 'ruby'), `echo "ruby $*" >> '${log}'; printf '2.6.10'`);
73
- if (opts.brewRuby) {
73
+ if (opts.brewRuby || opts.ruby33) {
74
+ const brewVersion = opts.brewRubyVersion ?? '3.4.1';
74
75
  const keg = join(root, 'homebrew-ruby');
75
- mkdirSync(join(keg, 'bin'), { recursive: true });
76
- executable(join(keg, 'bin', 'ruby'), `echo "brew-ruby $*" >> '${log}'; printf '3.4.1'`);
77
- executable(join(bin, 'brew'), `if [ "$*" = "--prefix --installed ruby" ]; then echo '${keg}'; exit 0; fi; exit 1`);
76
+ const keg33 = join(root, 'homebrew-ruby@3.3');
77
+ if (opts.brewRuby) {
78
+ mkdirSync(join(keg, 'bin'), { recursive: true });
79
+ executable(join(keg, 'bin', 'ruby'), `echo "brew-ruby $*" >> '${log}'; printf '${brewVersion}'`);
80
+ }
81
+ if (opts.ruby33) {
82
+ mkdirSync(join(keg33, 'bin'), { recursive: true });
83
+ executable(join(keg33, 'bin', 'ruby'), `echo "ruby33 $*" >> '${log}'; printf '3.3.10'`);
84
+ }
85
+ executable(join(bin, 'brew'), [
86
+ `if [ "$*" = "--prefix --installed ruby" ]; then ${opts.brewRuby ? `echo '${keg}'; exit 0` : 'exit 1'}; fi`,
87
+ `if [ "$*" = "list --versions ruby" ]; then ${opts.brewRuby ? `echo 'ruby ${brewVersion}'; exit 0` : 'exit 1'}; fi`,
88
+ `if [ "$*" = "--prefix --installed ruby@3.3" ]; then ${opts.ruby33 ? `echo '${keg33}'; exit 0` : 'exit 1'}; fi`,
89
+ 'exit 1',
90
+ ].join('\n'));
78
91
  }
79
92
  const script = (await new CocoapodsInstallStepExecutor().execute({ source_root_path: project }, {}, testConfig)).script;
80
93
  const scriptPath = join(root, 'step.sh');
@@ -154,7 +167,7 @@ describe('cocoapods-install runs the Ruby the project names', () => {
154
167
  expect(usedBrew(calls)).toBe(false);
155
168
  expect(calls).toContain('gem install bundler -v 2.3.21 --no-document');
156
169
  expect(calls.find((c) => c.startsWith('bundle _2.3.21_ install'))).toContain(`GEM_HOME=${gemHome}`);
157
- expect(output).toMatch(/^Ruby: .*\(2\.6\.10\), GEM_HOME: .* — system: lockfile names no Ruby$/m);
170
+ expect(output).toMatch(/^Ruby: .*\(2\.6\.10\), GEM_HOME: .* — system: lockfile names no Ruby, and no Ruby 3\.3 is installed$/m);
158
171
  });
159
172
  test('a lock whose RUBY VERSION is 3 or newer runs Homebrew Ruby', async () => {
160
173
  const { calls, output } = await run({ lock: lockWithRuby('3.3.4p94'), brewRuby: true });
@@ -204,4 +217,66 @@ describe('cocoapods-install runs the Ruby the project names', () => {
204
217
  expect(usedSystem(calls)).toBe(false);
205
218
  });
206
219
  });
220
+ // With the lock naming no Ruby, the step chose system Ruby 2.6 as above, and the build still died:
221
+ // the Xcode 26.4 SDK's Ruby 2.6 headers have no `ruby/config.h`, so no native extension (json, ffi)
222
+ // compiles. Homebrew's Ruby is 4, where the lock's rake 13.0.6 cannot load. So a Ruby 3.3 runs when
223
+ // the lock names no Ruby or one below 3; a named 3.x runs 3.3 unless Homebrew's matches it better; a
224
+ // named 4.x runs Homebrew's. A machine without 3.3 behaves as before.
225
+ describe('cocoapods-install runs Ruby 3.3 where system Ruby cannot build native gems', () => {
226
+ const used33 = (calls) => calls.some((c) => c.startsWith('ruby33'));
227
+ const usedBrew = (calls) => calls.some((c) => c.startsWith('brew-ruby'));
228
+ const usedSystem = (calls) => calls.some((c) => c.startsWith('ruby '));
229
+ const lockWithRuby = (v) => LOCK_WITH_BUNDLER.replace('BUNDLED WITH', `RUBY VERSION\n ruby ${v}\n\nBUNDLED WITH`);
230
+ const image = { brewRuby: true, brewRubyVersion: '4.0.2', ruby33: true };
231
+ test('a lock that names no Ruby runs 3.3, with the locked bundler', async () => {
232
+ const { calls, output, gemHome } = await run({ lock: LOCK_WITH_BUNDLER, ...image });
233
+ expect(used33(calls)).toBe(true);
234
+ expect(usedSystem(calls)).toBe(false);
235
+ expect(usedBrew(calls)).toBe(false);
236
+ expect(calls).toContain('gem install bundler -v 2.3.21 --no-document');
237
+ expect(calls.find((c) => c.startsWith('bundle _2.3.21_ install'))).toContain(`GEM_HOME=${gemHome}`);
238
+ expect(output).toMatch(/^Ruby: .*homebrew-ruby@3\.3\/bin\/ruby \(3\.3\.10\), GEM_HOME: .* — Ruby 3\.3: lockfile names no Ruby, and system Ruby 2\.6 cannot build native gems$/m);
239
+ });
240
+ test('a lock whose RUBY VERSION is 2.x runs 3.3', async () => {
241
+ const { calls, output } = await run({ lock: lockWithRuby('2.7.2p137'), ...image });
242
+ expect(used33(calls)).toBe(true);
243
+ expect(output).toContain('— from Gemfile.lock RUBY VERSION 2.7.2, run on Ruby 3.3: system Ruby 2.6 cannot build native gems');
244
+ });
245
+ test('a 2.x .ruby-version runs 3.3', async () => {
246
+ const { calls } = await run({ lock: LOCK_WITH_BUNDLER, rubyVersionFile: '2.7.6\n', ...image });
247
+ expect(used33(calls)).toBe(true);
248
+ });
249
+ test('a named 3.x that Homebrew does not match runs 3.3', async () => {
250
+ const { calls, output } = await run({ lock: lockWithRuby('3.2.2'), ...image });
251
+ expect(used33(calls)).toBe(true);
252
+ expect(usedBrew(calls)).toBe(false);
253
+ expect(output).toContain('— from Gemfile.lock RUBY VERSION 3.2.2, run on Ruby 3.3');
254
+ });
255
+ test('a named 3.3 runs 3.3 and needs no aside', async () => {
256
+ const { calls, output } = await run({ lock: lockWithRuby('3.3.4p94'), ...image });
257
+ expect(used33(calls)).toBe(true);
258
+ expect(output).toMatch(/— from Gemfile\.lock RUBY VERSION 3\.3\.4$/m);
259
+ });
260
+ test('a named 3.x that Homebrew matches runs Homebrew Ruby', async () => {
261
+ const { calls, output } = await run({ lock: lockWithRuby('3.4.1'), brewRuby: true, brewRubyVersion: '3.4.7', ruby33: true });
262
+ expect(usedBrew(calls)).toBe(true);
263
+ expect(used33(calls)).toBe(false);
264
+ expect(output).toMatch(/— from Gemfile\.lock RUBY VERSION 3\.4\.1$/m);
265
+ });
266
+ test('a named 4.x runs Homebrew Ruby', async () => {
267
+ const { calls } = await run({ lock: lockWithRuby('4.0.1'), ...image });
268
+ expect(usedBrew(calls)).toBe(true);
269
+ expect(used33(calls)).toBe(false);
270
+ });
271
+ test('without 3.3, a lock that names no Ruby runs system Ruby, and says 3.3 is missing', async () => {
272
+ const { calls, output } = await run({ lock: LOCK_WITH_BUNDLER, brewRuby: true, brewRubyVersion: '4.0.2' });
273
+ expect(usedSystem(calls)).toBe(true);
274
+ expect(output).toContain('— system: lockfile names no Ruby, and no Ruby 3.3 is installed');
275
+ });
276
+ test('without 3.3, a 2.x lock runs system Ruby, and says 3.3 is missing', async () => {
277
+ const { calls, output } = await run({ lock: lockWithRuby('2.7.2p137'), brewRuby: true });
278
+ expect(usedSystem(calls)).toBe(true);
279
+ expect(output).toContain('— from Gemfile.lock RUBY VERSION 2.7.2, and no Ruby 3.3 is installed');
280
+ });
281
+ });
207
282
  //# sourceMappingURL=cocoapods-locked-bundler.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ios-deps.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ios-deps.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,wBAAwB,CAAC;AAMhF,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,gBAAgB;IAChE,yBAAyB,CACvB,OAAO,EAAE,sBAAsB,EAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAUpB,OAAO,CACX,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAiLpB;AAMD,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,gBAAgB;IACxD,yBAAyB,CACvB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAUpB,OAAO,CACX,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAyDpB"}
1
+ {"version":3,"file":"ios-deps.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/ios-deps.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,wBAAwB,CAAC;AAMhF,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,gBAAgB;IAChE,yBAAyB,CACvB,OAAO,EAAE,sBAAsB,EAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAUpB,OAAO,CACX,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CA+MpB;AAMD,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,gBAAgB;IACxD,yBAAyB,CACvB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,qBAAqB,EAAE;IAUpB,OAAO,CACX,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,OAAO,CAAC;CAyDpB"}
@@ -83,14 +83,18 @@ export class CocoapodsInstallStepExecutor extends BaseStepExecutor {
83
83
  //
84
84
  // Three moves, each conditional, so a machine missing a piece keeps the
85
85
  // old behaviour rather than failing on it:
86
- // - run the Ruby the project names: Gemfile.lock's `RUBY VERSION`, then
87
- // `.ruby-version`. Only a named Ruby 3 or newer moves to Homebrew's
88
- // Ruby, which is keg-only, so not on PATH even where it is installed
89
- // (Homebrew's cocoapods and fastlane formulae depend on it). Anything
90
- // else, including a project that names none, stays on system Ruby 2.6.
91
- // Homebrew's is Ruby 4 on the mac image, and an old lockfile's gems do
92
- // not load there — rake 13.0.6 requires `ostruct`, no longer a default
93
- // gem — so "newest installed" is the wrong default;
86
+ // - run a Ruby that fits the one the project names: Gemfile.lock's
87
+ // `RUBY VERSION`, then `.ruby-version`. Homebrew's Ruby is 4 on the mac
88
+ // image, and an old lockfile's gems do not load there — rake 13.0.6
89
+ // requires `ostruct`, no longer a default gem — so "newest installed"
90
+ // is the wrong default. System Ruby 2.6 is no answer either: the Xcode
91
+ // 26.4 SDK's Ruby 2.6 headers have no `ruby/config.h`, so no native
92
+ // extension (json, ffi) compiles under it. So a Ruby named below 3, or
93
+ // none, runs a Homebrew `ruby@3.3`; a named 3.x runs 3.3 unless
94
+ // Homebrew's `ruby` has its major.minor; a named 4.x runs Homebrew's.
95
+ // Both are keg-only, so neither is on PATH where it is installed. With
96
+ // no 3.3 on the machine, below 3 stays on system Ruby and 3+ runs
97
+ // Homebrew's, as before. The `Ruby:` line says which, and why;
94
98
  // - point GEM_HOME at a writable directory outside the checkout, so both
95
99
  // `gem install bundler` and `bundle install` can write without sudo,
96
100
  // and put its bin directory first;
@@ -112,20 +116,46 @@ export class CocoapodsInstallStepExecutor extends BaseStepExecutor {
112
116
  commands.push(' case "${WANTED_RUBY%%.*}" in');
113
117
  commands.push(' \'\'|*[!0-9]*) WANTED_RUBY="" ;;');
114
118
  commands.push(' esac');
115
- commands.push(' if [ -z "$WANTED_RUBY" ]; then');
116
- commands.push(' RUBY_REASON="system: lockfile names no Ruby"');
117
- commands.push(' else');
118
- commands.push(' RUBY_REASON="from $WANTED_FROM $WANTED_RUBY"');
119
- commands.push(' if [ "${WANTED_RUBY%%.*}" -ge 3 ]; then');
119
+ commands.push(' # The Rubies this machine has: a Homebrew `ruby@3.3` keg, and Homebrew\'s');
120
+ commands.push(' # `ruby` with its major.minor. Both keg-only, so neither is on PATH.');
121
+ commands.push(' RUBY33=""');
122
+ commands.push(' BREW_RUBY=""');
123
+ commands.push(' BREW_RUBY_MM=""');
124
+ commands.push(' if command -v brew &>/dev/null; then');
125
+ commands.push(' RUBY33="$(brew --prefix --installed ruby@3.3 2>/dev/null || true)"');
126
+ commands.push(' if [ -n "$RUBY33" ] && [ ! -x "$RUBY33/bin/ruby" ]; then RUBY33=""; fi');
127
+ commands.push(' BREW_RUBY="$(brew --prefix --installed ruby 2>/dev/null || true)"');
128
+ commands.push(' if [ -n "$BREW_RUBY" ] && [ -x "$BREW_RUBY/bin/ruby" ]; then');
129
+ commands.push(' BREW_RUBY_MM="$(brew list --versions ruby 2>/dev/null | awk \'{ split($2, v, "."); print v[1] "." v[2]; exit }\')"');
130
+ commands.push(' else');
120
131
  commands.push(' BREW_RUBY=""');
121
- commands.push(' if command -v brew &>/dev/null; then');
122
- commands.push(' BREW_RUBY="$(brew --prefix --installed ruby 2>/dev/null || true)"');
123
- commands.push(' fi');
124
- commands.push(' if [ -n "$BREW_RUBY" ] && [ -x "$BREW_RUBY/bin/ruby" ]; then');
125
- commands.push(' export PATH="$BREW_RUBY/bin:$PATH"');
132
+ commands.push(' fi');
133
+ commands.push(' fi');
134
+ commands.push(' WANTED_MAJOR="${WANTED_RUBY%%.*}"');
135
+ commands.push(' WANTED_MM="$(printf \'%s\' "$WANTED_RUBY" | awk -F. \'{ print $1 "." $2 }\')"');
136
+ commands.push(' if [ -z "$WANTED_RUBY" ] || [ "$WANTED_MAJOR" -lt 3 ]; then');
137
+ commands.push(' if [ -z "$WANTED_RUBY" ]; then');
138
+ commands.push(' if [ -n "$RUBY33" ]; then');
139
+ commands.push(' export PATH="$RUBY33/bin:$PATH"');
140
+ commands.push(' RUBY_REASON="Ruby 3.3: lockfile names no Ruby, and system Ruby 2.6 cannot build native gems"');
126
141
  commands.push(' else');
127
- commands.push(' RUBY_REASON="$RUBY_REASON, but no Homebrew Ruby is installed"');
142
+ commands.push(' RUBY_REASON="system: lockfile names no Ruby, and no Ruby 3.3 is installed"');
128
143
  commands.push(' fi');
144
+ commands.push(' elif [ -n "$RUBY33" ]; then');
145
+ commands.push(' export PATH="$RUBY33/bin:$PATH"');
146
+ commands.push(' RUBY_REASON="from $WANTED_FROM $WANTED_RUBY, run on Ruby 3.3: system Ruby 2.6 cannot build native gems"');
147
+ commands.push(' else');
148
+ commands.push(' RUBY_REASON="from $WANTED_FROM $WANTED_RUBY, and no Ruby 3.3 is installed"');
149
+ commands.push(' fi');
150
+ commands.push(' else');
151
+ commands.push(' RUBY_REASON="from $WANTED_FROM $WANTED_RUBY"');
152
+ commands.push(' if [ "$WANTED_MAJOR" -eq 3 ] && [ -n "$RUBY33" ] && [ "$BREW_RUBY_MM" != "$WANTED_MM" ]; then');
153
+ commands.push(' export PATH="$RUBY33/bin:$PATH"');
154
+ commands.push(' [ "$WANTED_MM" != "3.3" ] && RUBY_REASON="$RUBY_REASON, run on Ruby 3.3"');
155
+ commands.push(' elif [ -n "$BREW_RUBY" ]; then');
156
+ commands.push(' export PATH="$BREW_RUBY/bin:$PATH"');
157
+ commands.push(' else');
158
+ commands.push(' RUBY_REASON="$RUBY_REASON, but no Homebrew Ruby is installed"');
129
159
  commands.push(' fi');
130
160
  commands.push(' fi');
131
161
  commands.push(' if ! command -v bundle &>/dev/null && ! command -v gem &>/dev/null; then');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invarn/cibuild",
3
- "version": "2.8.8",
3
+ "version": "2.8.9",
4
4
  "description": "CI Build CLI — local pipeline orchestration and validation",
5
5
  "type": "module",
6
6
  "main": "dist/cli.cjs",