Skip to content

Commit

Permalink
Distribute restatectl (#2606)
Browse files Browse the repository at this point in the history
* Release restatectl with other binaries

* Notarize apple binaries

* Add restatectl to cli docker image
  • Loading branch information
jackkleeman authored Feb 3, 2025
1 parent 86cd732 commit e5e3c78
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 19 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/docker-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,15 @@ jobs:
run: |
cat > Dockerfile << 'EOF'
FROM --platform=${BUILDPLATFORM} alpine as builder
ADD restate-cli-aarch64-unknown-linux-musl.tar.xz /restate-arm64
ADD restate-cli-x86_64-unknown-linux-musl.tar.xz /restate-amd64
# keep output image small by removing the server binary
RUN rm /restate-*/restate-server
ADD restate-cli-aarch64-unknown-linux-musl.tar.xz /restate-cli-arm64
ADD restatectl-aarch64-unknown-linux-musl.tar.xz /restatectl-arm64
ADD restate-cli-x86_64-unknown-linux-musl.tar.xz /restate-cli-amd64
ADD restatectl-x86_64-unknown-linux-musl.tar.xz /restatectl-amd64
FROM alpine
ARG TARGETARCH
COPY --from=builder /restate-${TARGETARCH} /
COPY --from=builder /restate-cli-${TARGETARCH} /
COPY --from=builder /restatectl-${TARGETARCH}/restatectl /
ENTRYPOINT [ "/restate" ]
EOF
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/notarize.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Notarize darwin binaries

on:
workflow_call:
inputs:
# comes from cargo-dist workflow call
plan:
required: true
type: string

env:
PLAN: ${{ inputs.plan }}

jobs:
notarize:
runs-on: warp-macos-latest-arm64-6x
strategy:
matrix:
app_name:
- restate-cli
- restatectl
- restate-server
target:
- aarch64-apple-darwin
- x86_64-apple-darwin

steps:
- name: Checkout
uses: actions/checkout@v4

- name: "Download GitHub Artifacts"
uses: actions/download-artifact@v4
with:
pattern: artifacts-*-apple-darwin
merge-multiple: true

- name: Extract binaries
run: tar -xvzf ${{ matrix.app_name }}-${{ matrix.target }}.tar.xz

- name: Add notary credentials
run: xcrun notarytool store-credentials --apple-id "$NOTARY_APPLE_ID" --password "$NOTARY_APP_SPECIFIC_PASSWORD" --team-id "$CODESIGN_IDENTITY" "Notarization"
env:
NOTARY_APPLE_ID: ${{ secrets.NOTARY_APPLE_ID }}
NOTARY_APP_SPECIFIC_PASSWORD: ${{ secrets.NOTARY_APP_SPECIFIC_PASSWORD }}
CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}

- name: Notarize
shell: bash
run: |
bin="$(echo "$PLAN" | jq -r '.artifacts["${{ matrix.app_name }}-${{ matrix.target }}.tar.xz"].assets[] | select(.kind == "executable").name')"
zip ${{ matrix.app_name }}-${{ matrix.target }}.zip "${{ matrix.app_name }}-${{ matrix.target }}/${bin}"
xcrun notarytool submit ${{ matrix.app_name }}-${{ matrix.target }}.zip --keychain-profile "Notarization"
15 changes: 9 additions & 6 deletions .github/workflows/npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
matrix:
app_name:
- restate-cli
- restatectl
- restate-server
build:
- target: aarch64-apple-darwin
Expand Down Expand Up @@ -57,7 +58,7 @@ jobs:
- name: Publish to NPM
shell: bash
run: |
bin="$(echo "$PLAN" | jq -r '.artifacts["${{ matrix.app_name }}-${{ matrix.build.target }}.tar.xz"].assets[] | select(.kind == "executable").name')
bin="$(echo "$PLAN" | jq -r '.artifacts["${{ matrix.app_name }}-${{ matrix.build.target }}.tar.xz"].assets[] | select(.kind == "executable").name')"
cd npm
node_os="${{ matrix.build.node_os }}"
Expand All @@ -78,10 +79,11 @@ jobs:
# generate package.json from the template
envsubst < package.json.tmpl > "${node_pkg}/package.json"
# copy the binary into the package
cp "../${bin}" "${node_pkg}/bin"
cp ../NOTICE "${node_pkg}"
cp ../LICENSE "${node_pkg}"
cp ../README.md "${node_pkg}"
dir="../${{ matrix.app_name }}-${{ matrix.target }}"
cp "${dir}/${bin}" "${node_pkg}/bin"
cp "${dir}/NOTICE" "${node_pkg}"
cp "${dir}/LICENSE" "${node_pkg}"
cp "${dir}/README.md" "${node_pkg}"
# publish the package
pushd "${node_pkg}"
npm publish --access public
Expand All @@ -96,6 +98,7 @@ jobs:
matrix:
app_name:
- restate-cli
- restatectl
- restate-server
steps:
- name: Checkout
Expand All @@ -110,7 +113,7 @@ jobs:
shell: bash
run: |
node_version=$(echo "$PLAN" | jq -r '.releases[] | select(.app_name == "${{ matrix.app_name }}").app_version')"
bin="$(echo "$PLAN" | jq -r '.artifacts["${{ matrix.package.artifact }}-${{ matrix.build.target }}.tar.xz"].assets[] | select(.kind == "executable").name')
bin="$(echo "$PLAN" | jq -r '.artifacts["${{ matrix.package.artifact }}-${{ matrix.build.target }}.tar.xz"].assets[] | select(.kind == "executable").name')"
cd npm
if npm view "@restatedev/${bin}@${node_version}"
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,24 @@ jobs:
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
custom-notarize:
needs:
- plan
- build-local-artifacts
uses: ./.github/workflows/notarize.yml
with:
plan: ${{ needs.plan.outputs.val }}
secrets: inherit
# Determines if we should publish/announce
host:
needs:
- plan
- build-local-artifacts
- build-global-artifacts
- custom-notarize
# Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-notarize.result == 'skipped' || needs.custom-notarize.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-20.04"
Expand Down Expand Up @@ -306,6 +316,7 @@ jobs:
- plan
- build-local-artifacts
- build-global-artifacts
- custom-notarize
uses: ./.github/workflows/ci.yml
with:
plan: ${{ needs.plan.outputs.val }}
Expand Down
1 change: 1 addition & 0 deletions dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ precise-builds = true
cache-builds = false

host-jobs = ["./ci"]
global-artifacts-jobs = ["./notarize"]
publish-jobs = ["./docker-release", "homebrew", "./npm"]
post-announce-jobs = ["./helm"]

Expand Down
20 changes: 17 additions & 3 deletions npm/restate-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
#!/usr/bin/env node

/*
* Copyright (c) 2023 - 2025 Restate Software, Inc., Restate GmbH.
* All rights reserved.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
* As of the Change Date specified in that file, in accordance with
* the Business Source License, use of this software will be governed
* by the Apache License, Version 2.0.
*/

import { spawnSync } from "child_process";
import os from 'node:os';
import os from "node:os";

function getExePath() {
const arch = os.arch();
const op = os.platform();

try {
return require.resolve(`@restatedev/restate-server-${op}-${arch}/bin/restate-server`);
return require.resolve(
`@restatedev/restate-server-${op}-${arch}/bin/restate-server`,
);
} catch (e) {
throw new Error(
`Couldn't find application binary inside node_modules for ${op}-${arch}`
`Couldn't find application binary inside node_modules for ${op}-${arch}`,
);
}
}
Expand Down
8 changes: 4 additions & 4 deletions npm/restate/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env node

/*
* Copyright (c) 2023 - 2025 Restate Software, Inc., Restate GmbH.
* All rights reserved.
Expand All @@ -10,10 +12,8 @@
* by the Apache License, Version 2.0.
*/

#!/usr/bin/env node

import { spawnSync } from "child_process";
import os from 'node:os';
import os from "node:os";

function getExePath() {
const arch = os.arch();
Expand All @@ -23,7 +23,7 @@ function getExePath() {
return require.resolve(`@restatedev/restate-${op}-${arch}/bin/restate`);
} catch (e) {
throw new Error(
`Couldn't find application binary inside node_modules for ${op}-${arch}`
`Couldn't find application binary inside node_modules for ${op}-${arch}`,
);
}
}
Expand Down
37 changes: 37 additions & 0 deletions npm/restatectl/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@restatedev/restatectl",
"description": "Restate administration tools",
"version": "0.5.1",
"bin": "lib/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/restatedev/restate.git"
},
"publishConfig": {
"@restatedev:registry": "https://registry.npmjs.org"
},
"author": "Restate Developers",
"license": "BSL",
"email": "code@restate.dev",
"homepage": "https://github.com/restatedev/restate#readme",
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"build": "tsc",
"dev": "npm run build && node lib/index.js"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"eslint": "^8.31.0",
"typescript": "^4.9.4"
},
"optionalDependencies": {
"@restatedev/restatectl-linux-x64": "0.5.1",
"@restatedev/restatectl-linux-arm64": "0.5.1",
"@restatedev/restatectl-darwin-x64": "0.5.1",
"@restatedev/restatectl-darwin-arm64": "0.5.1"
}
}
39 changes: 39 additions & 0 deletions npm/restatectl/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env node

/*
* Copyright (c) 2023 - 2025 Restate Software, Inc., Restate GmbH.
* All rights reserved.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
* As of the Change Date specified in that file, in accordance with
* the Business Source License, use of this software will be governed
* by the Apache License, Version 2.0.
*/

import { spawnSync } from "child_process";
import os from "node:os";

function getExePath() {
const arch = os.arch();
const op = os.platform();

try {
return require.resolve(
`@restatedev/restatectl-${op}-${arch}/bin/restatectl`,
);
} catch (e) {
throw new Error(
`Couldn't find application binary inside node_modules for ${op}-${arch}`,
);
}
}

function run() {
const args = process.argv.slice(2);
const processResult = spawnSync(getExePath(), args, { stdio: "inherit" });
process.exit(processResult.status ?? 0);
}

run();
12 changes: 12 additions & 0 deletions npm/restatectl/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"baseUrl": "./",
"outDir": "lib",
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
7 changes: 7 additions & 0 deletions tools/restatectl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@
name = "restatectl"
version.workspace = true
authors.workspace = true
description = "Restate administration tools"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
publish = false

[package.metadata.dist]
dist = true
formula = "restatectl"

[features]
default = ["replicated-loglet", "memory-loglet", "no-trace-logging"]
replicated-loglet = [
Expand Down

0 comments on commit e5e3c78

Please sign in to comment.