diff --git a/generate-release-notes/README.md b/generate-release-notes/README.md new file mode 100644 index 0000000..37b5c3e --- /dev/null +++ b/generate-release-notes/README.md @@ -0,0 +1,39 @@ +# generate-release-notes + +Collects the git commit log between two refs and generates human-readable release notes using [Opencode](https://opencode.ai) with AWS Bedrock. + +## Inputs + +| Input | Required | Default | Description | +|-------|----------|---------|-------------| +| `bedrock-bearer-token` | Yes | — | AWS Bedrock bearer token for Opencode | +| `base-ref` | Yes | — | Base branch for git log comparison (e.g. `main` or `dev`) | +| `head-ref` | Yes | — | Head branch for git log comparison (e.g. `HEAD` or `dev`) | +| `section-title` | Yes | — | Title for the commits section in the generated markdown | +| `empty-message` | Yes | — | Message to include when no commits are found | +| `include-diff-stat` | No | `true` | Include a "Changed files" section with `git diff --stat` output | + +## Outputs + +| Output | Description | +|--------|-------------| +| `release-note` | The generated release notes as a markdown string | + +## Usage + +```yaml +- id: notes + uses: https://schmalz-git.git.onstackit.cloud/schmalz/shared-actions/generate-release-notes@generate-release-notes-v1 + with: + bedrock-bearer-token: ${{ secrets.BEDROCK_BEARER_TOKEN }} + base-ref: main + head-ref: HEAD + section-title: My Service + empty-message: No changes since last release. +``` + +## Notes + +- Requires the repository to be checked out with enough history for the comparison (use `fetch-depth: 0` in the `checkout` action). +- Release notes are generated in German and categorised into 💡 Features, 🪲 Bugfixes, and 🧹 Wartung based on conventional commit prefixes. +- The output can be passed directly to the `publish-release-notes-via-webhook` action via `${{ steps.notes.outputs.release-note }}`. diff --git a/generate-release-notes/action.yml b/generate-release-notes/action.yml new file mode 100644 index 0000000..3790f30 --- /dev/null +++ b/generate-release-notes/action.yml @@ -0,0 +1,92 @@ +name: Generate Release Notes +description: Collects git diff and generates release notes using GitHub Copilot CLI + +inputs: + bedrock-bearer-token: + description: AWS Bedrock Bearer token for Opencode + required: true + base-ref: + description: Base branch name for git log comparison (e.g. "dev" or "main") + required: true + head-ref: + description: Head branch name for git log comparison (e.g. "HEAD" or "dev") + required: true + section-title: + description: Title for the commits section in the generated markdown + required: true + empty-message: + description: Message to include when no commits are found + required: true + include-diff-stat: + description: Include a "Changed files" section with git diff --stat output + default: 'true' + +outputs: + release-note: + description: The generated release notes as a markdown string + value: ${{ steps.generate.outputs.release-note }} + +runs: + using: composite + steps: + - name: Collect diff + shell: bash + run: | + git fetch origin ${{ inputs.base-ref }} ${{ inputs.head-ref }} + + BASE_REF="origin/${{ inputs.base-ref }}" + HEAD_REF="${{ inputs.head-ref }}" + [[ "$HEAD_REF" != "HEAD" ]] && HEAD_REF="origin/$HEAD_REF" + + BRANCH_COMMITS=$(git log $BASE_REF..$HEAD_REF \ + --pretty=format:"- %h %s (%an, %ad)" \ + --date=short) + + { + echo "## ${{ inputs.section-title }}" + echo "" + echo "### Commits" + echo "" + if [ -z "$BRANCH_COMMITS" ]; then + echo "${{ inputs.empty-message }}" + else + echo "$BRANCH_COMMITS" + fi + } > commits.md + + if [ "${{ inputs.include-diff-stat }}" = "true" ]; then + DIFF_STAT=$(git diff --stat $BASE_REF...$HEAD_REF) + { + echo "" + echo "### Changed files" + echo "" + if [ -z "$DIFF_STAT" ]; then + echo "No file changes found." + else + echo "$DIFF_STAT" + fi + } >> commits.md + fi + + echo "--- commits.md ---" + cat commits.md + + - name: Write Copilot output to Markdown + id: generate + shell: bash + env: + AWS_BEARER_TOKEN_BEDROCK: ${{ inputs.bedrock-bearer-token }} + PROMPT: "Erstelle Release Notes auf Basis der folgenden Commit-Liste. Release Notes bestehen aus einer Aufzählung mit jeweils einem Aufzählungspunkt pro Änderung. Die Aufzählung wird eingeleitet mit \"Folgende Änderungen wurden in Betrieb genommen:\". Die Änderungen sind nach Art der Änderung sortiert. Es gibt 3 Kategorien: \"💡 Features\", \"🪲 Bugfixes\" und \"🧹 Wartung\". Zu welcher Kategorie eine Änderung gehört, hängt vom Präfix der zugehörigen Commitnachricht ab. Wenn es zu einer Kategorie keine Änderungen gibt, wird sie weggelassen. Am Anfang jedes Punkts steht eine kurze, fettgedruckte Zusammenfassung der Änderung. Danach steht eine sachliche Beschreibung der Änderung in ganzen Sätzen. Sie richtet sich an ein nicht technisches Publikum, das aber mit der Materie vertraut ist (Product Owner, UX Designer, Team Lead). Beschränke dich daher aufs Wesentliche und verschweige technische Einzelheiten. Vermeide Abkürzungen, wenn du deren Bedeutung kennst. Bevorzuge aber die englischen Fachbegriffe. Am Ende jeder Änderung erwähne in Klammern den Autor sowie die referenzierten Ticketnummern, sofern vorhanden. Jira Tickets sollen mit Link eingefügt werden: https://jira.schmalz.com/browse/" + run: | + curl -fsSL https://opencode.ai/install | bash + COMMITS=$(cat commits.md) + AWS_BEARER_TOKEN_BEDROCK=$AWS_BEARER_TOKEN_BEDROCK opencode run "$PROMPT $COMMITS" > release-notes.md + + echo "--- release-notes.md ---" + cat release-notes.md + + { + echo "release-note<> "$GITHUB_OUTPUT" diff --git a/publish-release-notes-via-webhook/README.md b/publish-release-notes-via-webhook/README.md new file mode 100644 index 0000000..59d40a4 --- /dev/null +++ b/publish-release-notes-via-webhook/README.md @@ -0,0 +1,44 @@ +# publish-release-notes-via-webhook + +Sends release notes to a Microsoft Teams channel via a Power Automate webhook. + +## Inputs + +| Input | Required | Default | Description | +|-------|----------|---------|-------------| +| `service-name` | Yes | — | Name of the service included in the webhook payload | +| `release-note` | Yes | — | Release notes markdown content to publish | +| `request-url` | Yes | — | Power Automate webhook URL | + +## Usage + +```yaml +- uses: https://schmalz-git.git.onstackit.cloud/schmalz/shared-actions/publish-release-notes-via-webhook@publish-release-notes-via-webhook-v1 + with: + service-name: my-service + release-note: ${{ steps.notes.outputs.release-note }} + request-url: ${{ secrets.TEAMS_WEBHOOK_URL }} +``` + +## Webhook Payload + +The action sends a `POST` request with the following JSON body: + +```json +{ + "servicename": "my-service", + "releasenote": "Folgende Änderungen wurden in Betrieb genommen:\n..." +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `servicename` | string | Value of the `service-name` input | +| `releasenote` | string | Value of the `release-note` input (markdown) | + +The Power Automate flow must accept a `POST` request with `Content-Type: application/json` and handle both fields. + +## Notes + +- Designed to be used together with the `generate-release-notes` action, which exposes the `release-note` output. +- The webhook URL should be stored as a secret and never hardcoded in the workflow. diff --git a/publish-release-notes-via-webhook/action.yml b/publish-release-notes-via-webhook/action.yml new file mode 100644 index 0000000..830a770 --- /dev/null +++ b/publish-release-notes-via-webhook/action.yml @@ -0,0 +1,41 @@ +name: Publish Release Notes with Webhook +description: Sends generated release notes to a Teams webhook via Power Automate + +inputs: + service-name: + description: Name of the service for the webhook payload + required: true + release-note: + description: The release notes markdown content to publish + required: true + request-url: + description: Power Automate webhook URL + required: true + +runs: + using: composite + steps: + - name: Trigger Teams Webhook with release notes + shell: bash + env: + SERVICE_NAME: ${{ inputs.service-name }} + RELEASE_NOTE: ${{ inputs.release-note }} + REQUEST_URL: ${{ inputs.request-url }} + run: | + RELEASE_NOTE_CONTENT="$RELEASE_NOTE" + + WEBHOOK_PAYLOAD=$(jq -n \ + --arg servicename "$SERVICE_NAME" \ + --arg releasenote "$RELEASE_NOTE_CONTENT" \ + '{ + "servicename": ($servicename), + "releasenote": ($releasenote) + }') + + WEBHOOK_RESPONSE=$(curl -s -w "\n__HTTP_STATUS__:%{http_code}" -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + "$REQUEST_URL" \ + -d "$WEBHOOK_PAYLOAD") + + echo "Webhook response: $WEBHOOK_RESPONSE"