diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 2e239a4..bd9d294 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -1,17 +1,37 @@ name: CD + on: push: - tags: - - "v[0-9]+.[0-9]+.[0-9]+" branches: - - docs + - production + tags-ignore: + - "**" jobs: - launch: + release: + permissions: + contents: write + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - - run: | - curl -X POST -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ - https://api.github.com/repos/${{ secrets.BUILDER }}/dispatches \ - -d '{"event_type":"deploy", "client_payload":{"branch": "${{ github.ref_name }}"}}' + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2 + bundler-cache: true + + - uses: actions/setup-node@v4 + with: + node-version: latest + + - run: npm install + - run: npx semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }} + + publish: + needs: release + uses: ./.github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..20e4691 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,17 @@ +name: Publish + +on: + push: + branches: + - docs + workflow_call: + +jobs: + launch: + runs-on: ubuntu-latest + steps: + - run: | + curl -X POST -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ + https://api.github.com/repos/${{ secrets.BUILDER }}/dispatches \ + -d '{"event_type":"deploy", "client_payload":{"branch": "${{ github.ref_name }}"}}' diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8a686ab..8f28580 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,7 +1,5 @@ # Changelog -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - ## [6.5.5](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.4...v6.5.5) (2024-03-23) ### Bug Fixes diff --git a/package.json b/package.json index b023362..79b8161 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,15 @@ "@commitlint/config-conventional": "^19.1.0", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-terser": "^0.4.4", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^6.0.3", + "@semantic-release/git": "^10.0.1", + "conventional-changelog-conventionalcommits": "^7.0.2", "husky": "^9.0.11", "rimraf": "^5.0.5", "rollup": "^4.13.2", "rollup-plugin-license": "^3.3.1", + "semantic-release": "^23.0.8", "stylelint": "^16.3.1", "stylelint-config-standard-scss": "^13.0.0" }, @@ -89,24 +94,76 @@ "media-feature-range-notation": "prefix" } }, - "standard-version": { - "skip": { - "commit": true, - "tag": true - }, - "types": [ - { - "type": "feat", - "section": "Features" - }, - { - "type": "fix", - "section": "Bug Fixes" - }, - { - "type": "perf", - "section": "Improvements" - } + "release": { + "branches": [ + "production" + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "presetConfig": { + "types": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Improvements" + }, + { + "type": "refactor", + "section": "Changes", + "hidden": true + } + ] + } + } + ], + [ + "@semantic-release/changelog", + { + "changelogFile": "docs/CHANGELOG.md", + "changelogTitle": "# Changelog" + } + ], + [ + "@semantic-release/npm", + { + "npmPublish": false + } + ], + [ + "@semantic-release/exec", + { + "prepareCmd": "bash tools/release --prepare", + "publishCmd": "bash tools/release" + } + ], + [ + "@semantic-release/git", + { + "assets": [ + "docs", + "package.json", + "*.gemspec" + ], + "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" + } + ], + "@semantic-release/github" ] } } diff --git a/tools/release b/tools/release index 965828b..90b1823 100755 --- a/tools/release +++ b/tools/release @@ -1,56 +1,47 @@ #!/usr/bin/env bash # -# Release a new version to the GitLab flow production branch. -# -# For a new major/minor version, bump version on the main branch, and then merge into the production branch. -# -# For a patch version, bump the version number on the patch branch, then merge that branch into the main branch -# and production branch. -# -# -# Usage: run on the default, release or the patch branch -# # Requires: Git, NPM and RubyGems set -eu -opt_pre=false # preview mode option +opt_pre=false # option for bump gem version +opt_pkg=false # option for building gem package -working_branch="$(git branch --show-current)" - -DEFAULT_BRANCH="$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')" - -PROD_BRANCH="production" +MAIN_BRANCH="master" +RELEASE_BRANCH="production" GEM_SPEC="jekyll-theme-chirpy.gemspec" -NODE_CONFIG="package.json" -CHANGE_LOG="docs/CHANGELOG.md" +NODE_SPEC="package.json" +CHANGELOG="docs/CHANGELOG.md" +CONFIG="_config.yml" JS_DIST="assets/js/dist" -BACKUP_PATH="$(mktemp -d)" FILES=( "$GEM_SPEC" - "$NODE_CONFIG" + "$NODE_SPEC" + "$CHANGELOG" + "$CONFIG" ) TOOLS=( "git" "npm" - "standard-version" "gem" ) help() { - echo "A tool to release new version Chirpy gem" + echo -e "A tool to release new version Chirpy gem.\nThis tool will:" + echo " 1. Build a new gem and publish it to RubyGems.org" + echo " 2. Merge the release branch into the default branch" echo echo "Usage:" - echo - echo " bash ./tools/release [options]" + echo " bash ./tools/release [options]" echo echo "Options:" - echo " -p, --preview Enable preview mode, only package, and will not modify the branches" - echo " -h, --help Print this information." + echo " --prepare Preparation for release" + echo " -p, --package Build a gem package only, for local packaging in case of auto-publishing failure" + echo " -h, --help Display this help message" } _check_cli() { @@ -70,11 +61,9 @@ _check_git() { exit 1 fi - $opt_pre || ( - if [[ $working_branch != "$DEFAULT_BRANCH" && - $working_branch != hotfix/* && - $working_branch != "$PROD_BRANCH" ]]; then - echo "> Abort: Please run on the default, release or patch branch." + $opt_pkg || ( + if [[ "$(git branch --show-current)" != "$RELEASE_BRANCH" ]]; then + echo "> Abort: Please run the tool in the '$RELEASE_BRANCH' branch." exit 1 fi ) @@ -103,108 +92,95 @@ check() { _check_node_packages } -# Auto-generate a new version number to the file 'package.json' -bump_node() { - bump="standard-version -i $CHANGE_LOG" +## Bump new version to gem-spec file +_bump_version() { + _version="$(grep '"version":' "$NODE_SPEC" | sed 's/.*: "//;s/".*//')" + sed -i "s/[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/$_version/" "$GEM_SPEC" + echo "> Bump gem version to $_version" +} - if $opt_pre; then - bump="$bump -p rc" - fi - - eval "$bump" - - # Change heading of Patch version to heading level 2 (a bug from `standard-version`) - sed -i "s/^### \[/## \[/g" "$CHANGE_LOG" +_improve_changelog() { # Replace multiple empty lines with a single empty line - sed -i "/^$/N;/^\n$/D" "$CHANGE_LOG" + sed -i '/^$/N;/^\n$/D' "$CHANGELOG" + # Escape left angle brackets of HTML tag in the changelog as they break the markdown structure. e.g., '
' + sed -i -E 's/\s(<[a-z])/ \\\1/g' "$CHANGELOG" } -## Bump new version to gem config file -bump_gem() { - _ver="$1" - - if $opt_pre; then - _ver="${1/-/.}" - fi - - sed -i "s/[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/$_ver/" "$GEM_SPEC" -} - -# Creates a new tag on the production branch with the given version number. -# Also commits the changes and merges the production branch into the default branch. -branch() { - _version="$1" # X.Y.Z - - git add . - git commit -m "chore(release): $_version" - - # Create a new tag on production branch - echo -e "> Create tag v$_version\n" - git tag "v$_version" - - git checkout "$DEFAULT_BRANCH" - git merge --no-ff --no-edit "$PROD_BRANCH" - - if [[ $working_branch == hotfix/* ]]; then - # delete the patch branch - git branch -D "$working_branch" - fi +prepare() { + _bump_version + _improve_changelog } ## Build a Gem package build_gem() { - git checkout "$PROD_BRANCH" + if $opt_pkg; then + BACKUP_PATH="$(mktemp -d)" + cp "$JS_DIST"/* "$BACKUP_PATH" + fi # Remove unnecessary theme settings - sed -i "s/^cdn:.*/cdn:/;s/^avatar:.*/avatar:/" _config.yml + sed -i "s/^cdn:.*/cdn:/;s/^avatar:.*/avatar:/" $CONFIG rm -f ./*.gem npm run build git add "$JS_DIST" -f # add JS distribution files to gem gem build "$GEM_SPEC" - cp "$JS_DIST"/* "$BACKUP_PATH" - # Resume the settings + # resume the settings git reset git checkout . - # restore the dist files for future development - mkdir -p "$JS_DIST" && cp "$BACKUP_PATH"/* "$JS_DIST" + if $opt_pkg; then + # restore the dist files for future development + mkdir -p "$JS_DIST" && cp "$BACKUP_PATH"/* "$JS_DIST" + rm -rf "$BACKUP_PATH" + fi +} - # back to the default branch - git checkout "$DEFAULT_BRANCH" +# Push the gem to RubyGems.org (using $GEM_HOST_API_KEY) +push_gem() { + gem push ./*.gem +} + +## Merge the release branch into the default branch +merge() { + git fetch origin "$MAIN_BRANCH" + git checkout -b "$MAIN_BRANCH" origin/"$MAIN_BRANCH" + + git merge --no-ff --no-edit "$RELEASE_BRANCH" || ( + git merge --abort + echo -e "\n> Conflict detected. Aborting merge.\n" + exit 0 + ) + + git push origin "$MAIN_BRANCH" } main() { check - if [[ $opt_pre = false && $working_branch != "$PROD_BRANCH" ]]; then - git checkout "$PROD_BRANCH" - git merge --no-ff --no-edit "$working_branch" + if $opt_pre; then + prepare + exit 0 fi - bump_node - - _version="$(grep '"version":' "$NODE_CONFIG" | sed 's/.*: "//;s/".*//')" - - bump_gem "$_version" - - if [[ $opt_pre = false ]]; then - branch "$_version" - fi - - echo -e "> Build the gem package for v$_version\n" - build_gem + $opt_pkg && exit 0 + push_gem + merge } while (($#)); do opt="$1" case $opt in - -p | --preview) + --prepare) opt_pre=true shift ;; + -p | --package) + opt_pkg=true + shift + ;; -h | --help) help exit 0