Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .config/wasm-pkg/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[namespace_registries]
wasi = "wasi.dev"
componentized = "componentized.dev"
7 changes: 0 additions & 7 deletions .devcontainer/Dockerfile

This file was deleted.

15 changes: 4 additions & 11 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
{
"name": "cli",
"build": {
"dockerfile": "Dockerfile"
},

"name": "componentized-cli",
"image": "mcr.microsoft.com/devcontainers/rust",
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
"mounts": [
{
Expand All @@ -19,15 +16,12 @@
"type": "volume"
}
],

// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "cargo check",

"postCreateCommand": "./scripts/init-devcontainer.sh",
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
Expand All @@ -47,7 +41,6 @@
]
}
}

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
}
36 changes: 20 additions & 16 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
- package-ecosystem: cargo
directory: "/"
schedule:
interval: daily
- package-ecosystem: rust-toolchain
directory: "/"
schedule:
interval: daily
- package-ecosystem: devcontainers
directory: "/"
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
- package-ecosystem: cargo
directory: "/"
schedule:
interval: daily
- package-ecosystem: cargo
directory: "/tools"
schedule:
interval: daily
- package-ecosystem: rust-toolchain
directory: "/"
schedule:
interval: daily
- package-ecosystem: devcontainers
directory: "/"
schedule:
interval: weekly
203 changes: 203 additions & 0 deletions .github/workflows/bump-version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
name: Bump version

on:
workflow_dispatch:
inputs:
version:
description: The new version of the interface package, e.g. 0.2.0 or 0.3.0-dev
required: true
type: string
default: "0.2.0-dev" # the current version, kept current by scripts/bump-version.sh

jobs:
# bumps the version with read only access, the changes are handed to the push job as a patch so
# the third party actions used to build never run with write access
bump:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check version
# a semver version without a leading `v`, the tag adds it. Build metadata is used to tag the
# debug builds of components, e.g. 0.1.0+debug, and isn't allowed in the version itself.
run: |
identifier='(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)'
semver="^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-${identifier}(\.${identifier})*)?$"
if ! [[ "${VERSION}" =~ ${semver} ]] ; then
echo "::error::the version '${VERSION}' is not a valid semver version, e.g. 0.2.0 or 0.3.0-dev"
exit 1
fi
if [[ "${VERSION}" == *+* ]] ; then
echo "::error::the version '${VERSION}' must not contain build metadata"
exit 1
fi
env:
VERSION: ${{ inputs.version }}
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions-rust-lang/setup-rust-toolchain@v2
- name: Install cargo binstall
uses: cargo-bins/cargo-binstall@main
- name: Install tools
run: |
make tools
make -s tools-path >> "${GITHUB_PATH}"
- name: Bump version
# also fetches the wit dependencies for the new version, and builds and tests the components
run: scripts/bump-version.sh "${VERSION}"
env:
VERSION: ${{ inputs.version }}
- name: Collect changes
run: |
git add --all
git diff --cached --binary > bump-version.patch
- name: Upload changes
uses: actions/upload-artifact@v7
with:
name: bump-version.patch
path: bump-version.patch
if-no-files-found: error
retention-days: 1

# pushes the bump to the branch the workflow was run on, using only first party actions and the gh
# cli
push:
needs:
- bump
# the bump is a new commit on the branch, a tag can't be moved forward
if: github.ref_type == 'branch'
runs-on: ubuntu-latest
# the commit is pushed with a token for the custodian GitHub App rather than the GITHUB_TOKEN,
# which can't change workflow files and doesn't trigger the CI workflow. The app must be allowed
# to bypass the branch's ruleset, the commit is pushed without the status checks it requires,
# the bump job built and tested the changes instead.
permissions:
contents: read
env:
VERSION: ${{ inputs.version }}
steps:
- name: Check custodian app credentials
run: |
if [ -z "${CLIENT_ID}" ] || [ -z "${PRIVATE_KEY}" ] ; then
echo "::error::the CUSTODIAN_CLIENT_ID and CUSTODIAN_PRIVATE_KEY secrets must be available to this repository, the private key of the custodian GitHub App is needed to create a token"
exit 1
fi
env:
CLIENT_ID: ${{ secrets.CUSTODIAN_CLIENT_ID }}
PRIVATE_KEY: ${{ secrets.CUSTODIAN_PRIVATE_KEY }}
- name: Create custodian app token
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ secrets.CUSTODIAN_CLIENT_ID }}
private-key: ${{ secrets.CUSTODIAN_PRIVATE_KEY }}
# only this repository, with only the permissions the bump needs
repositories: ${{ github.event.repository.name }}
permission-contents: write
# the bump changes the default version in this workflow
permission-workflows: write
# a release runs this workflow again, to bump to the next dev version
permission-actions: write
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Download changes
uses: actions/download-artifact@v8
with:
name: bump-version.patch
path: ${{ runner.temp }}
- name: Read current version
# the checkout is before the bump, the wit package's version is the current version
run: |
current=$( sed -n 's/^package componentized:cli@\(.*\);$/\1/p' wit/worlds.wit )
echo "CURRENT_VERSION=${current}" >> "${GITHUB_ENV}"
- name: Commit changes
# the commit is created with the REST API, as the app's token can't push. The patch is applied
# locally only to find the changed files and their modes.
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
run: |
api="repos/${GITHUB_REPOSITORY}"
base=$( git rev-parse HEAD )
git apply --index "${RUNNER_TEMP}/bump-version.patch"

# a blob for each changed file, or a null sha for a deleted file
entries="${RUNNER_TEMP}/tree-entries.json"
echo '[]' > "${entries}"
git diff --cached --no-renames --name-status "${base}" | while IFS=$'\t' read -r status path ; do
if [ "${status}" = "D" ] ; then
entry=$( jq -n --arg path "${path}" '{path: $path, mode: "100644", type: "blob", sha: null}' )
else
mode=$( git ls-files --stage -- "${path}" | cut -d' ' -f1 )
sha=$( base64 < "${path}" | tr -d '\n' | jq -Rs '{encoding: "base64", content: .}' | gh api --method POST "${api}/git/blobs" --input - --jq .sha )
entry=$( jq -n --arg path "${path}" --arg mode "${mode}" --arg sha "${sha}" '{path: $path, mode: $mode, type: "blob", sha: $sha}' )
fi
jq --argjson entry "${entry}" '. + [$entry]' "${entries}" > "${entries}.tmp" && mv "${entries}.tmp" "${entries}"
echo "${status} ${path}"
done
tree=$( jq --arg base "$( git rev-parse "${base}^{tree}" )" '{base_tree: $base, tree: .}' "${entries}" | gh api --method POST "${api}/git/trees" --input - --jq .sha )

# authored, committed and signed off (DCO) by the custodian app's bot. GitHub only signs
# commits it attributes entirely to the app, so the author and committer are left for GitHub
# to fill in. The user who triggered the workflow is credited as a co-author, with their
# GitHub noreply email so their email address isn't exposed. A run started by the app after a
# release has no one else to credit.
bot="${APP_SLUG}[bot]"
bot_email="$( gh api "users/${bot}" --jq .id )+${bot}@users.noreply.github.com"
message=$( printf 'Bump version from %s to %s\n\nSigned-off-by: %s <%s>' "${CURRENT_VERSION}" "${VERSION}" "${bot}" "${bot_email}" )
if [ "${GITHUB_ACTOR}" != "${bot}" ] ; then
name=$( gh api "users/${GITHUB_ACTOR}" --jq '.name // .login' )
name="${name:-${GITHUB_ACTOR}}"
email="${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com"
message=$( printf '%s\nCo-authored-by: %s <%s>' "${message}" "${name}" "${email}" )
fi
read -r commit verified < <( jq -n \
--arg message "${message}" \
--arg tree "${tree}" --arg parent "${base}" \
'{message: $message, tree: $tree, parents: [$parent]}' \
| gh api --method POST "${api}/git/commits" --input - --jq '"\(.sha) \(.verification.verified)"' )
echo "created commit ${commit}"
# the branch requires signed commits, fail before pushing rather than after
if [ "${verified}" != "true" ] ; then
echo "::error::the commit '${commit}' was not created, or was not signed by GitHub"
exit 1
fi

# a release, rather than a pre-release, is tagged, e.g. v0.1.0. Tags are immutable, check the
# tag is free before pushing the branch, so a release isn't left without its tag
tag=""
if [[ "${VERSION}" != *-* ]] ; then
tag="v${VERSION}"
if gh api "${api}/git/ref/tags/${tag}" --silent 2> /dev/null ; then
echo "::error::the tag ${tag} already exists"
exit 1
fi
fi

# fast forwards the branch to the commit, failing rather than losing commits pushed to the
# branch since the workflow started
if ! gh api --method PATCH "${api}/git/refs/heads/${GITHUB_REF_NAME}" -f sha="${commit}" -F force=false --silent ; then
echo "::error::failed to push ${commit} to ${GITHUB_REF_NAME}, either the branch moved since ${base} and the workflow should be run again, or the custodian app is not allowed to bypass the branch's ruleset"
exit 1
fi
echo "pushed ${commit} to ${GITHUB_REF_NAME}"

# a lightweight tag, pushed with the app's token so the CI workflow runs for it and drafts
# the release
if [ -n "${tag}" ] ; then
gh api --method POST "${api}/git/refs" -f ref="refs/tags/${tag}" -f sha="${commit}" --silent
echo "tagged ${commit} as ${tag}"
fi
- name: Bump to the next dev version
# after a release, the branch moves on to a pre-release of the next patch version, e.g. 0.3.0
# is followed by 0.3.1-dev. Run with the app's token, the GITHUB_TOKEN can't start workflows.
if: ${{ !contains(inputs.version, '-') }}
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
IFS=. read -r major minor patch <<< "${VERSION}"
next="${major}.${minor}.$(( patch + 1 ))-dev"
gh workflow run bump-version.yaml --repo "${GITHUB_REPOSITORY}" --ref "${GITHUB_REF_NAME}" -f version="${next}"
echo "started the ${GITHUB_WORKFLOW} workflow for ${next} on ${GITHUB_REF_NAME}"
Loading
Loading