Skip to content
Draft
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
59 changes: 0 additions & 59 deletions .deploy/tag.js

This file was deleted.

9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
commit-message:
prefix: chore
include: scope
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI

on:
pull_request:
push:
branches:
- master

permissions:
contents: read

jobs:
commitlint:
runs-on: ubuntu-latest
steps:
# Squash merges use the PR title as the commit message, so lint the title.
# Keep `scopes` in sync with commitlint.config.js
- name: Lint PR title
if: github.event_name == 'pull_request'
uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
requireScope: false
scopes: |
api
get
cli
deps
ci
release
repo

- uses: actions/checkout@v4
if: github.event_name == 'push'
with:
fetch-depth: 0

- uses: actions/setup-node@v4
if: github.event_name == 'push'
with:
node-version: '22.20'

- name: Install
if: github.event_name == 'push'
run: yarn install --immutable

# Fails after the fact: it cannot block a direct push, only make the violation visible
- name: Lint pushed commits
if: github.event_name == 'push'
env:
BEFORE: ${{ github.event.before }}
AFTER: ${{ github.sha }}
run: |
if [[ "$BEFORE" =~ ^0+$ ]] || ! git cat-file -e "${BEFORE}^{commit}" 2>/dev/null; then
# first push of a branch, or force push over history we no longer have
yarn commitlint --last
else
yarn commitlint --from "$BEFORE" --to "$AFTER"
fi

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22.20'

- name: Install
run: yarn install --immutable

- name: Cache turbo
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ hashFiles('yarn.lock') }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-${{ hashFiles('yarn.lock') }}-

- name: Build
run: yarn turbo run build
141 changes: 100 additions & 41 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,65 +1,124 @@
name: Release

on:
push:
tags:
branches:
- master

permissions:
id-token: write
contents: write
pull-requests: write
id-token: write

# A run's tags must exist before the next run's release-please reads them
concurrency:
group: release
cancel-in-progress: false

jobs:
release:
release-please:
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') }}
outputs:
cli_release_created: ${{ steps.rp.outputs['cli--release_created'] }}
cli_tag_name: ${{ steps.rp.outputs['cli--tag_name'] }}
steps:
# A PAT or GitHub App token, not GITHUB_TOKEN, so CI runs on the release PR
- uses: googleapis/release-please-action@v4
id: rp
with:
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

# Libraries skip GitHub Releases, so release-please outputs never signal them.
# A version missing from npm always means a pending release.
publish-libs:
needs: release-please
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [api, get]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22.20'
registry-url: 'https://registry.npmjs.org'
- name: Get Tag
id: tag
run: |
echo "value=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Get Package
id: package

- name: Check npm
id: check
run: |
TAG="${{ steps.tag.outputs.value }}"
if [[ "$TAG" =~ @ ]]; then
PACKAGE="$(echo "$TAG" | sed -e 's#@[0-9].[0-9].[0-9]$##')"
NAME="$(node -p "require('./${{ matrix.package }}/package.json').name")"
VERSION="$(node -p "require('./${{ matrix.package }}/package.json').version")"
echo "name=$NAME" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
if [ "$(npm view "$NAME@$VERSION" version 2>/dev/null)" = "$VERSION" ]; then
echo "published=true" >> "$GITHUB_OUTPUT"
else
PACKAGE="@shift-code/cli"
echo "published=false" >> "$GITHUB_OUTPUT"
fi
echo "value=$PACKAGE" >> $GITHUB_OUTPUT
- name: Get Version
id: version
run: |
TAG="${{ steps.tag.outputs.value }}"
VERSION="$(echo "$TAG" | sed -e 's#.*\([0-9].[0-9].[0-9]$\)#\1#')"
echo "value=$VERSION" >> $GITHUB_OUTPUT
- name: Get Changes
id: changes

- name: Install
if: steps.check.outputs.published == 'false'
run: yarn install --immutable

- name: Build
if: steps.check.outputs.published == 'false'
run: yarn turbo run build --filter=${{ steps.check.outputs.name }}

- name: Publish
if: steps.check.outputs.published == 'false'
run: yarn workspace ${{ steps.check.outputs.name }} npm publish

- name: Tag
if: steps.check.outputs.published == 'false'
env:
TAG: ${{ steps.check.outputs.name }}@${{ steps.check.outputs.version }}
run: |
CHANGES=$(git log --graph --pretty=format:'%h - %s' "$(git describe --abbrev=0 --tags $(git describe --tags --abbrev=0)^)"..HEAD | cat)
echo "value=$CHANGES" >> $GITHUB_OUTPUT
if [ -z "$(git ls-remote --tags origin "refs/tags/$TAG")" ]; then
git tag "$TAG"
git push origin "refs/tags/$TAG"
fi

# Must run after publish-libs: the published cli manifest references the new library versions
publish-cli:
needs: [release-please, publish-libs]
if: always() && needs.release-please.outputs.cli_release_created == 'true' && needs.publish-libs.result == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22.20'
registry-url: 'https://registry.npmjs.org'

- name: Install
run: yarn install
run: yarn install --immutable

- name: Build
run: yarn workspace ${{ steps.package.outputs.value }} run build
run: yarn turbo run build --filter=@shift-code/cli

- name: Publish
run: |
VERSION="$(node -p "require('./cli/package.json').version")"
if [ "$(npm view "@shift-code/cli@$VERSION" version 2>/dev/null)" = "$VERSION" ]; then
echo "@shift-code/cli@$VERSION already published"
else
yarn workspace @shift-code/cli npm publish
fi

- name: Package
if: ${{ steps.package.outputs.value == '@shift-code/cli' }}
run: |
yarn workspace ${{ steps.package.outputs.value }} run pkg
yarn turbo run pkg --filter=@shift-code/cli
for file in cli/pkg/cli-*; do
mv "$file" "$(echo "$file" | sed -e s#cli-#shift-code-#)"
mv "$file" "$(echo "$file" | sed -e 's#cli-#shift-code-#')"
done
- name: Release
if: ${{ steps.package.outputs.value == '@shift-code/cli' }}
uses: softprops/action-gh-release@v1
with:
body: ${{ steps.changes.outputs.value }}
files: cli/pkg/*
- name: Publish
run: |
git config user.email "git@tylerstewart.ca"
git config user.name "Tyler Stewart"
yarn workspace ${{ steps.package.outputs.value }} npm publish

- name: Upload binaries
env:
GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }}
TAG: ${{ needs.release-please.outputs.cli_tag_name }}
run: gh release upload "$TAG" cli/pkg/* --clobber
22 changes: 16 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
node_modules/
dist/
pkg/

.env
tsconfig.tsbuildinfo
# yarn
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*

node_modules/
dist/
pkg/
.turbo/

.env
tsconfig.tsbuildinfo
1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yarn commitlint --edit "$1"
5 changes: 5 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"api": "0.6.4",
"get": "0.7.2",
"cli": "1.3.7"
}
Binary file removed .yarn/install-state.gz
Binary file not shown.
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,24 @@ If you're a developer, some of the other packages might interest you in creating
</tr>
</table>

## Development

- `yarn install` sets up the workspace and the commit-msg hook
- `yarn build` builds all packages in dependency order
- `yarn dev -- <command>` runs the cli in dev mode, eg: `yarn dev -- redeem`

## Deployment

- Run `yarn run tag <package> <strategy>`
- eg: `yarn run tag cli minor`
- Version will be changed and a tag will be created
- Tag and commit are then pushed
- Workflow triggers on tag, publishing to NPM and creating a Github release
Releases are automated with [release-please](https://github.com/googleapis/release-please), driven by [conventional commits](https://www.conventionalcommits.org).

- Commit messages, and PR titles for squash merges, must look like `type(scope): subject`
- scope is optional: `api`, `get`, `cli`, `deps`, `ci`, `release`, `repo`
- `fix` makes a patch release, `feat` a minor release, and `!` or a `BREAKING CHANGE` footer a major release
- other types (`chore`, `docs`, `ci`, ...) do not release; to ship a dependency fix, use `fix(deps): ...`
- A commit-msg hook lints commits locally; CI lints PR titles and pushes to `master`
- Pushing releasable commits to `master` opens or updates a release PR with version bumps and changelogs
- releasing `api` or `get` also releases `cli`
- Merging the release PR triggers the release workflow
- `api` and `get` are published to NPM and tagged (`@shift-code/<name>@<version>`)
- `cli` is published to NPM, tagged (`v<version>`), and a Github release is created with the binaries attached
- If a release job fails, re-run the failed jobs; every step is safe to repeat
Loading
Loading