diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 122724f7..73e0301c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,3 +5,4 @@ # the repo. Unless a later match takes precedence. * @newrelic/coreint +* @newrelic/caos diff --git a/.github/workflows/push_pr.yaml b/.github/workflows/push_pr.yaml index 72d138c8..3663b2a1 100644 --- a/.github/workflows/push_pr.yaml +++ b/.github/workflows/push_pr.yaml @@ -1,15 +1,11 @@ name: Push/PR pipeline on: pull_request: - push: - branches: - - main jobs: rebase: name: Branch needs rebase runs-on: ubuntu-latest - if: github.event.pull_request steps: - uses: actions/checkout@v4 with: @@ -51,8 +47,20 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check if CHANGELOG is valid uses: ./validate-markdown + - name: Generate YAML for the changelog + uses: ./generate-yaml + - name: Check if the release is not needed + id: empty + uses: ./is-empty + - run: | + if [[ "${{ steps.empty.outputs.is-empty }}" == "true" ]]; then + echo "Release is empty, failing" >&2 + exit 1 + fi static-analysis: name: Static analysis and linting diff --git a/.github/workflows/self_test.yaml b/.github/workflows/self_test.yaml index c3eb72dd..c20f8b26 100644 --- a/.github/workflows/self_test.yaml +++ b/.github/workflows/self_test.yaml @@ -215,7 +215,6 @@ jobs: yaml: ${{ env.MOCK_REPO }}/changelog.yaml markdown: ${{ env.MOCK_REPO }}/CHANGELOG.md git-root: ${{ env.MOCK_REPO }} - exit-code: 0 - run: | if [[ "${{ steps.generate-yaml.outputs.empty-changelog }}" != "true" ]]; then echo "empty-changelog should have returned true" >&2 @@ -503,253 +502,3 @@ jobs: echo "valid should have returned false" >&2 exit 1 fi - - contrib-ohi-release-notes: - name: validate ohi-release-notes (contrib action) - runs-on: ubuntu-latest - env: - MOCK_REPO_ACTION: ./mock_repo_action - MOCK_REPO_SCRIPT: ./mock_repo_script - ACTION_OUTPUTS: ./action_outputs - steps: - - uses: actions/checkout@v4 - - name: Configure test repo - shell: bash - run: | - # MOCK_REPO_SCRIPT is not needed as it is copied from ACTION one. - mkdir -pv "${MOCK_REPO_ACTION}" "${ACTION_OUTPUTS}" - cd "${MOCK_REPO_ACTION}" - - git config --global user.email "you@example.com" - git config --global user.name "Your Name" - - git init - cat > CHANGELOG.md < CHANGELOG.md < expected-changelog.md < expected-partial.md < CHANGELOG.md - echo -ne "${{ steps.ohi-release-notes.outputs.changelog-partial }}" > CHANGELOG.partial.md - - - name: Asserts - run: | - exit_status=0 - - echo "Action's CHANGELOG.md should be equal" - echo RESULT: - cat "${{ env.MOCK_REPO_ACTION }}/CHANGELOG.md" - echo EXPECTED: - cat expected-changelog.md - echo TEST: - if cmp --silent expected-changelog.md ${{ env.MOCK_REPO_ACTION }}/CHANGELOG.md; then - echo PASS - else - echo FAIL - diff between expected and the output: - diff expected-changelog.md ${{ env.MOCK_REPO_ACTION }}/CHANGELOG.md - ((exit_status++)) - fi - echo ================================================================= - echo "script's CHANGELOG.md should be equal" - echo RESULT: - cat "${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.md" - echo EXPECTED: - cat expected-changelog.md - echo TEST: - if cmp --silent expected-changelog.md ${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.md; then - echo PASS - else - echo FAIL - diff between expected and the output: - diff expected-changelog.md ${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.md - ((exit_status++)) - fi - echo ================================================================= - echo "script's CHANGELOG.md should be equal" - echo RESULT: - cat "${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.md" - echo EXPECTED: - cat expected-changelog.md - echo TEST: - if cmp --silent expected-changelog.md ${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.md; then - echo PASS - else - echo FAIL - diff between expected and the output: - diff expected-changelog.md ${{ env.ACTION_OUTPUTS }}/CHANGELOG.md - ((exit_status++)) - fi - echo ================================================================= - echo "Action's CHANGELOG.partial.md should be equal" - echo RESULT: - cat "${{ env.MOCK_REPO_ACTION }}/CHANGELOG.partial.md" - echo EXPECTED: - cat expected-partial.md - echo TEST: - if cmp --silent expected-partial.md ${{ env.MOCK_REPO_ACTION }}/CHANGELOG.partial.md; then - echo PASS - else - echo FAIL - diff between expected and the output: - diff expected-partial.md ${{ env.MOCK_REPO_ACTION }}/CHANGELOG.partial.md - ((exit_status++)) - fi - echo ================================================================= - echo "script's CHANGELOG.partial.md should be equal" - echo RESULT: - cat "${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.partial.md" - echo EXPECTED: - cat expected-partial.md - echo TEST: - if cmp --silent expected-partial.md ${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.partial.md; then - echo PASS - else - echo FAIL - diff between expected and the output: - diff expected-partial.md ${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.partial.md - ((exit_status++)) - fi - echo ================================================================= - echo "script's CHANGELOG.partial.md should be equal" - echo RESULT: - cat "${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.partial.md" - echo EXPECTED: - cat expected-partial.md - echo TEST: - if cmp --silent expected-partial.md ${{ env.MOCK_REPO_SCRIPT }}/CHANGELOG.partial.md; then - echo PASS - else - echo FAIL - diff between expected and the output: - diff expected-partial.md ${{ env.ACTION_OUTPUTS }}/CHANGELOG.partial.md - ((exit_status++)) - fi - echo ================================================================= - echo "action output 'next-version' return the expected value" - echo EXPECTED: - echo "v2.0.0" - echo RESULT: - echo "${{ steps.ohi-release-notes.outputs.next-version }}" - echo TEST: - if [ "${{ steps.ohi-release-notes.outputs.next-version }}" = "v2.0.0" ] ; then - echo PASS - else - echo FAIL - action output 'next-version' does not return the expected value - ((exit_status++)) - fi - echo ================================================================= - echo "action output 'release-title' return the expected value" - echo EXPECTED: - echo "v2.0.0 - $(date +%Y-%m-%d)" - echo RESULT: - echo "${{ steps.ohi-release-notes.outputs.release-title }}" - echo TEST: - if [ "${{ steps.ohi-release-notes.outputs.release-title }}" = "v2.0.0 - $(date +%Y-%m-%d)" ] ; then - echo PASS - else - echo FAIL - action output 'release-title' does not return the expected value - ((exit_status++)) - fi - - exit $exit_status diff --git a/CHANGELOG.md b/CHANGELOG.md index 544e8bfb..91d63a08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,32 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). Unreleased section should follow [Release Toolkit](https://github.com/newrelic/release-toolkit#render-markdown-and-update-markdown) + ## Unreleased +### Notes + +`ohi-release-notes` action was only used by Coreint team and it has been moved to their repository: +[`coreint-automation` PR](https://github.com/newrelic/coreint-automation/pull/83) + +`generate-yaml` failed to create an empty YAML by default. The composable nature of `release-toolkit` +encourages the user to hack the YAML if needed. This is also needed so an empty YAML is there for the +other actions like `is-empty` or `is-held` to work properly. + +`next-version` should also follow the composable nature of `release-toolkit`. But this part of the tool +should fail if there is no new version in case a user hack the YAML to a point that is not bumping the +version. Not failing can lead scripts to override an already existing version. This is also a change +on the default behavior. + +### Breaking +- `ohi-release-notes` action has been moved to another repository +- `generate-yaml` does not fail to create an empty YAML by default +- `next-version` fail if there are no version to be bumped + +### Bugfix +- Upgrade golang and project dependencies to the latest version +- Change use of deprecated print `::set-output` to write to `$GITHUB_OUTPUT` file + ## v1.2.0 - 2024-08-09 ### 🚀 Enhancements diff --git a/Dockerfile b/Dockerfile index a36923c6..9944f963 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Builder for GHA does not use BUILDKIT, so we cannot use a multiarch-friendly builder image. # FROM --platform=$BUILDPLATFORM golang:1.18-alpine as builder -FROM golang:1.22.0-alpine as builder +FROM golang:1.23.2-alpine as builder WORKDIR /rt COPY go.* ./ @@ -12,6 +12,6 @@ COPY src src RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /bin/rt -FROM alpine as runner +FROM alpine:3.20.3 as runner COPY --from=builder /bin/rt /bin/rt ENTRYPOINT [ "/bin/rt" ] diff --git a/README.md b/README.md index c972cfbb..a5798633 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ name: Release workflow on: workflow-dispatch: jobs: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # This is important to have all the commits and tags - name: Generate transient changelog.yaml uses: newrelic/release-toolkit/generate-yaml@v1 with: diff --git a/contrib/ohi-release-notes/README.md b/contrib/ohi-release-notes/README.md deleted file mode 100644 index 772f4915..00000000 --- a/contrib/ohi-release-notes/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# 🛠️ `ohi-release-notes` - -This is a wrapper of all the steps needed to update the changelog and render a snippet to be ready to be used as a release message. This contribution also includes a script that allow to replicate what this action does locally. - -## Example Usage - -```yaml -- uses: newrelic/release-toolkit/contrib/ohi-release-notes@v1 - id: release -- name: Commit updated changelog - run: | - git add CHANGELOG.md - git commit -m "Update changelog with changes from ${{ steps.release.outputs.next-version }}" - git push -u origin main - gh release create ${{ steps.release.outputs.release-title }} --target $(git rev-parse HEAD) --notes-file CHANGELOG.partial.md -``` - -## Parameters - -All parameters are optional: - * `excluded-dirs` exclude commits whose changes only impact files in specified dirs relative to repository root. Defaults to ".github". - * `excluded-files` Exclude commits whose changes only impact files in specified files relative to repository root. Defaults to "". - * `included-dirs` Only scan commits scoping at least one file in any of the following comma-separated directories - * `included-files` Only scan commits scoping at least one file in the following comma-separated list - * `fail-if-held` fails if the held toggle is active - * `dictionary` sets the link dependency dictionary file path. Defaults to ".github/rt-dictionary.yml". - * `excluded-dependencies-manifest` sets the excluded dependencies manifest. Defaults to ".github/excluded-dependencies.yml". - -## Outputs - - * `next-version` contains the calculated version for this. - * `release-title` is the title of the release that includes `next-version` and the date it was done. - * `release-changelog` contains the complete changelog of this release. Alias of the file `CHANGELOG.md` - * `release-changelog-partial` contains the changelog for only this release. Alias of the file `CHANGELOG.partial.md` - -This action also leaves the files `CHANGELOG.md` and `CHANGELOG.partial.md` at the working directory so they are also ready to be committed. - -## Use script locally -There is a `run.sh` script that should do the same as this action: Leaves the files `CHANGELOG.md` and `CHANGELOG.partial.md` at the working directory and prints the title of the release with the next version and the date. - -You can run it by bashpipeing this script: -```shell -curl "https://raw.githubusercontent.com/newrelic/release-toolkit/v1/contrib/ohi-release-notes/run.sh" | bash -``` - -## Contributing - -Standard policy and procedure across the New Relic GitHub organization. - -#### Useful Links -* [Code of Conduct](../CODE_OF_CONDUCT.md) -* [Security Policy](../SECURITY.md) -* [License](../LICENSE) - -## Support - -New Relic has open-sourced this project. This project is provided AS-IS WITHOUT WARRANTY OR DEDICATED SUPPORT. Issues and contributions should be reported to the project here on GitHub. - -We encourage you to bring your experiences and questions to the [Explorers Hub](https://discuss.newrelic.com) where our community members collaborate on solutions and new ideas. - -## License - -release-toolkit is licensed under the [Apache 2.0](http://apache.org/licenses/LICENSE-2.0.txt) License. - -## Disclaimer - -This tool is provided by New Relic AS IS, without warranty of any kind. New Relic does not guarantee that the tool will: not cause any disruption to services or systems; provide results that are complete or 100% accurate; correct or cure any detected vulnerability; or provide specific remediation advice. diff --git a/contrib/ohi-release-notes/action.yml b/contrib/ohi-release-notes/action.yml deleted file mode 100644 index 3c87d2d6..00000000 --- a/contrib/ohi-release-notes/action.yml +++ /dev/null @@ -1,151 +0,0 @@ -name: OHI release notes -description: Wrapper for release toolkit that runs commands needed to release an OHI -inputs: - git-root: - description: Path to the root of the git repository to source bot commits from. - default: "." - excluded-dirs: - description: Exclude commits whose changes only impact files in specified dirs relative to repository root. Defaults to ".github". - default: '.github' - excluded-files: - description: Exclude commits whose changes only impact files in specified files relative to repository root. Defaults to "". - default: '' - included-dirs: - description: Only scan commits scoping at least one file in any of the following comma-separated directories - required: false - default: "" - included-files: - description: Only scan commits scoping at least one file in the following comma-separated list - required: false - default: "" - fail-if-held: - description: Fail if the held toggle is active. Defaults to `true`. - default: 'true' - link-dependencies-dictionary: - description: Sets the link dependency dictionary. `.github/rt-dictionary.yml` is used by default, if it does not exist a common dictionary is used. - default: '.github/rt-dictionary.yml' - excluded-dependencies-manifest: - description: Excluded dependencies manifest. Dependency commits containing any of the strings listed, will be excluded. Defaults to `.github/excluded-dependencies.yml`. - default: '.github/excluded-dependencies.yml' -outputs: - is-empty: - description: "Outputs if changelog is empty" - value: ${{ steps.empty.outputs.is-empty }} - is-held: - description: "Outputs if changelog is held" - value: ${{ steps.held.outputs.is-held }} - skip-release: - description: "Outputs if a release should be skipped" - value: ${{ steps.check-release.outputs.skip }} - next-version: - description: "Version of this release" - value: ${{ steps.version.outputs.next-version }} - release-title: - description: "Title of this release" - value: ${{ steps.release.outputs.title }} - release-changelog: - description: "Complete changelog of this release" - value: ${{ steps.release.outputs.changelog }} - release-changelog-partial: - description: "Changelog for only this release" - value: ${{ steps.release.outputs.changelog-partial }} -runs: - using: composite - steps: - - name: Validate that the markdown is correct - uses: newrelic/release-toolkit/validate-markdown@v1 - with: - markdown: ${{ inputs.git-root }}/CHANGELOG.md - # excluded-dependencies is a file contained by this action and is located inside $GITHUB_ACTION_PATH, but this - # folder is not mounted in the container that runs the generate-yaml action, so we copied the file to - # ${GITHUB_WORKSPACE} which is mounted in the container. - - name: Copy dependencies file to temp folder mounted by the generate-yaml action - shell: bash - run: | - if ! [ -f "${GITHUB_WORKSPACE}/${{ inputs.excluded-dependencies-manifest }}" ]; then - cp ${{ github.action_path }}/excluded-dependencies.yml "${GITHUB_WORKSPACE}/${{ inputs.excluded-dependencies-manifest }}" - fi - - name: Generate YAML - uses: newrelic/release-toolkit/generate-yaml@v1 - with: - excluded-dirs: ${{ inputs.excluded-dirs }} - excluded-files: ${{ inputs.excluded-files }} - included-dirs: ${{ inputs.included-dirs }} - included-files: ${{ inputs.included-files }} - excluded-dependencies-manifest: ${{ inputs.excluded-dependencies-manifest }} - git-root: ${{ inputs.git-root }} - markdown: ${{ inputs.git-root }}/CHANGELOG.md - yaml: ${{ inputs.git-root }}/changelog.yaml - exit-code: "0" - - name: Check if the release is empty - id: empty - uses: newrelic/release-toolkit/is-empty@v1 - with: - yaml: ${{ inputs.git-root }}/changelog.yaml - - name: Check if the release is held - id: held - uses: newrelic/release-toolkit/is-held@v1 - with: - yaml: ${{ inputs.git-root }}/changelog.yaml - - name: Check if the release should be skipped - id: check-release - shell: bash - run: | - echo "::set-output name=skip::${{ steps.empty.outputs.is-empty == 'true' || steps.held.outputs.is-held == 'true' }}" - # rt-dictionary is a file contained by this action and is located inside $GITHUB_ACTION_PATH, but this - # folder is not mounted in the container that runs the link-dependencies action, so we copied the file to - # ${GITHUB_WORKSPACE} which is mounted in the container. - - name: Copy dictionary to temp folder mounted by the link-dependencies action - shell: bash - run: | - if ! [ -f "${GITHUB_WORKSPACE}/${{ inputs.link-dependencies-dictionary }}" ]; then - cp ${{ github.action_path }}/rt-dictionary.yml "${GITHUB_WORKSPACE}/${{ inputs.link-dependencies-dictionary }}" - fi - - name: Link dependencies - if: ${{ steps.check-release.outputs.skip != 'true' }} - uses: newrelic/release-toolkit/link-dependencies@v1 - with: - # see comment from last step regarding this file. - dictionary: ${{ inputs.link-dependencies-dictionary }} - yaml: ${{ inputs.git-root }}/changelog.yaml - - name: Calculate next version - if: ${{ steps.check-release.outputs.skip != 'true' }} - id: version - uses: newrelic/release-toolkit/next-version@v1 - with: - git-root: ${{ inputs.git-root }} - yaml: ${{ inputs.git-root }}/changelog.yaml - - name: Update the markdown - if: ${{ steps.check-release.outputs.skip != 'true' }} - uses: newrelic/release-toolkit/update-markdown@v1 - with: - markdown: ${{ inputs.git-root }}/CHANGELOG.md - yaml: ${{ inputs.git-root }}/changelog.yaml - version: ${{ steps.version.outputs.next-version }} - - name: Render the changelog snippet - if: ${{ steps.check-release.outputs.skip != 'true' }} - uses: newrelic/release-toolkit/render@v1 - with: - markdown: ${{ inputs.git-root }}/CHANGELOG.partial.md - yaml: ${{ inputs.git-root }}/changelog.yaml - version: ${{ steps.version.outputs.next-version }} - - name: Create outputs - if: ${{ steps.check-release.outputs.skip != 'true' }} - shell: bash - id: release - run: | - echo "title=$(grep -E "^## " ${{ inputs.git-root }}/CHANGELOG.partial.md | sed 's|^## ||')" >> $GITHUB_OUTPUT - - echo "changelog-partial<> $GITHUB_OUTPUT - cat ${{ inputs.git-root }}/CHANGELOG.partial.md >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - echo "changelog<> $GITHUB_OUTPUT - cat ${{ inputs.git-root }}/CHANGELOG.md >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - name: Clean the workspace - if: ${{ steps.check-release.outputs.skip != 'true' }} - shell: bash - run: | - rm ${{ inputs.git-root }}/CHANGELOG.md.bak - rm ${{ inputs.git-root }}/changelog.yaml diff --git a/contrib/ohi-release-notes/excluded-dependencies.yml b/contrib/ohi-release-notes/excluded-dependencies.yml deleted file mode 100644 index 58ac0b2c..00000000 --- a/contrib/ohi-release-notes/excluded-dependencies.yml +++ /dev/null @@ -1,4 +0,0 @@ -# This contains a list of development dependencies that should be skipped from the changelog. -dependencies: - - github.com/stretchr/testify - - github.com/testcontainers/testcontainers-go diff --git a/contrib/ohi-release-notes/rt-dictionary.yml b/contrib/ohi-release-notes/rt-dictionary.yml deleted file mode 100644 index 6f382787..00000000 --- a/contrib/ohi-release-notes/rt-dictionary.yml +++ /dev/null @@ -1,32 +0,0 @@ -# This file is a dictionary used by the [link-dependencies](https://github.com/newrelic/release-toolkit/tree/main/link-dependencies) action. -# Notice that the implementation uses dep.To.ToString that removes the leading v if present. -dictionary: - newrelic/infrastructure-bundle: "https://github.com/newrelic/infrastructure-bundle/releases/tag/v{{.To}}" - newrelic/infrastructure: "https://github.com/newrelic/infrastructure-agent/releases/tag/{{.To}}" - newrelic/nri-apache: "https://github.com/newrelic/nri-apache/releases/tag/v{{.To}}" - newrelic/nri-cassandra: "https://github.com/newrelic/nri-cassandra/releases/tag/v{{.To}}" - newrelic/nri-consul: "https://github.com/newrelic/nri-consul/releases/tag/v{{.To}}" - newrelic/nri-couchbase: "https://github.com/newrelic/nri-couchbase/releases/tag/v{{.To}}" - newrelic/nri-discovery-kubernetes: "https://github.com/newrelic/nri-discovery-kubernetes/releases/tag/v{{.To}}" - newrelic/nri-docker: "https://github.com/newrelic/nri-docker/releases/tag/v{{.To}}" - newrelic/nri-ecs: "https://github.com/newrelic/nri-ecs/releases/tag/v{{.To}}" - newrelic/nri-elasticsearch: "https://github.com/newrelic/nri-elasticsearch/releases/tag/v{{.To}}" - newrelic/nri-f5: "https://github.com/newrelic/nri-f5/releases/tag/v{{.To}}" - newrelic/nri-haproxy: "https://github.com/newrelic/nri-haproxy/releases/tag/v{{.To}}" - newrelic/nri-jmx: "https://github.com/newrelic/nri-jmx/releases/tag/v{{.To}}" - newrelic/nri-kafka: "https://github.com/newrelic/nri-kafka/releases/tag/v{{.To}}" - newrelic/nri-memcached: "https://github.com/newrelic/nri-memcached/releases/tag/v{{.To}}" - newrelic/nri-mongodb: "https://github.com/newrelic/nri-mongodb/releases/tag/v{{.To}}" - newrelic/nri-mssql: "https://github.com/newrelic/nri-mssql/releases/tag/v{{.To}}" - newrelic/nri-mysql: "https://github.com/newrelic/nri-mysql/releases/tag/v{{.To}}" - newrelic/nri-nagios: "https://github.com/newrelic/nri-nagios/releases/tag/v{{.To}}" - newrelic/nri-nginx: "https://github.com/newrelic/nri-nginx/releases/tag/v{{.To}}" - newrelic/nri-oracledb: "https://github.com/newrelic/nri-oracledb/releases/tag/v{{.To}}" - newrelic/nri-postgresql: "https://github.com/newrelic/nri-postgresql/releases/tag/v{{.To}}" - newrelic/nri-prometheus: "https://github.com/newrelic/nri-prometheus/releases/tag/v{{.To}}" - newrelic/nri-rabbitmq: "https://github.com/newrelic/nri-rabbitmq/releases/tag/v{{.To}}" - newrelic/nri-redis: "https://github.com/newrelic/nri-redis/releases/tag/v{{.To}}" - newrelic/nri-varnish: "https://github.com/newrelic/nri-varnish/releases/tag/v{{.To}}" - newrelic/nri-winservices: "https://github.com/newrelic/nri-winservices/releases/tag/v{{.To}}" - newrelic/nrjmx: "https://github.com/newrelic/nrjmx/releases/tag/v{{.To}}" - newrelic/prometheus-exporter-supervisor: "https://github.com/newrelic/prometheus-exporter-supervisor/releases/tag/v{{.To}}" diff --git a/contrib/ohi-release-notes/run.sh b/contrib/ohi-release-notes/run.sh deleted file mode 100755 index 927234ac..00000000 --- a/contrib/ohi-release-notes/run.sh +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -RT_PKG="github.com/newrelic/release-toolkit@latest" -DICTIONARY_URL="https://raw.githubusercontent.com/newrelic/release-toolkit/v1/contrib/ohi-release-notes/rt-dictionary.yml" -EXCLUDED_DEPENDENCIES_MANIFEST_URL="https://raw.githubusercontent.com/newrelic/release-toolkit/v1/contrib/ohi-release-notes/excluded-dependencies.yml" -ARGS="$*" - - -# creating a temporary folder where to build the rt binary and cleaning after exiting. -TEMP_DIR=$(mktemp -dt release-toolkit-XXX) -function cleanup() { - rm -rf $TEMP_DIR || true - rm "${GIT_ROOT}/CHANGELOG.md.bak" || true - rm "${GIT_ROOT}/changelog.yaml" || true -} -trap cleanup EXIT - - -# usage and help command. It is also an error exit in case flags are not correct. -function help() { - set +x # Disable verbosity. If it is enabled at this point, it is not needed anymore. - ERRNO=0 - if ! [ -z "${1:-}" ]; then - echo "ERROR:" - echo " $1" - echo "" - ERRNO=1 - fi - - cat < /dev/null - ${RT_BIN} is-held "${IS_HELD_FAIL}" > /dev/null - if [ -f "$DICTIONARY" ]; then - ${RT_BIN} link-dependencies --dictionary "$DICTIONARY" - else - ${RT_BIN} link-dependencies - fi - NEXT_VERSION="$(${RT_BIN} next-version)" - ${RT_BIN} update-markdown --version "$NEXT_VERSION" - ${RT_BIN} render-changelog --version "$NEXT_VERSION" - - echo "Release title should be: $(grep -E "^## " CHANGELOG.partial.md | sed 's|^## ||')" -) diff --git a/generate-yaml/action.yml b/generate-yaml/action.yml index 4bbf1152..f94bc5dc 100644 --- a/generate-yaml/action.yml +++ b/generate-yaml/action.yml @@ -48,7 +48,7 @@ inputs: exit-code: description: Exit code if changelog is empty required: false - default: "1" + default: "0" runs: using: docker image: ../Dockerfile diff --git a/go.mod b/go.mod index 749d19b8..a4c3eb72 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,37 @@ module github.com/newrelic/release-toolkit -go 1.19 +go 1.23.2 require ( github.com/Masterminds/semver v1.5.0 - github.com/gomarkdown/markdown v0.0.0-20220627144906-e9a81102ebeb + github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8 github.com/google/go-cmp v0.5.9 github.com/h2non/gock v1.2.0 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.0 - github.com/urfave/cli/v2 v2.16.3 + github.com/urfave/cli/v2 v2.27.5 gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emirpasic/gods v1.12.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sergi/go-diff v1.0.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect github.com/src-d/gcfg v1.4.0 // indirect - github.com/xanzy/ssh-agent v0.2.1 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.15.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 5a606230..a4bf9a88 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,28 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gomarkdown/markdown v0.0.0-20220627144906-e9a81102ebeb h1:5b/eFaSaKPFG9ygDBaPKkydKU5nFJYk08g9jPIVogMg= -github.com/gomarkdown/markdown v0.0.0-20220627144906-e9a81102ebeb/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8 h1:4txT5G2kqVAKMjzidIabL/8KqjIK71yj30YOeuxLn10= +github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -29,8 +33,9 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplb github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -48,53 +53,70 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk= -github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= -github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= @@ -103,6 +125,8 @@ gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/testutil/gha_output.go b/internal/testutil/gha_output.go new file mode 100644 index 00000000..5de27813 --- /dev/null +++ b/internal/testutil/gha_output.go @@ -0,0 +1,40 @@ +package testutil + +import ( + "io" + "os" + "path" + "testing" + + "github.com/newrelic/release-toolkit/src/app/gha" +) + +type GithubOutputWriter struct { + File *os.File +} + +func NewGithubOutputWriter(t *testing.T) GithubOutputWriter { + t.Helper() + + ghaOutputFileName := path.Join(t.TempDir(), "temporary_github_output_file") + t.Setenv(gha.GithubOutput, ghaOutputFileName) + + ghaOutputFile, err := os.Create(ghaOutputFileName) + if err != nil { + t.Fatalf("Error creating temporary GHA output file for test: %v", err) + } + + return GithubOutputWriter{ + File: ghaOutputFile, + } +} + +func (ghaOut GithubOutputWriter) Result(t *testing.T) string { + t.Helper() + + actual, err := io.ReadAll(ghaOut.File) + if err != nil { + t.Fatalf("Unable to read temporary GHA output file: %v", err) + } + return string(actual) +} diff --git a/next-version/action.yml b/next-version/action.yml index 0264869b..8574ce4c 100644 --- a/next-version/action.yml +++ b/next-version/action.yml @@ -20,7 +20,7 @@ inputs: fail: description: Fail if no new version found, by default the current version will be returned in that case required: false - default: "0" + default: "1" outputs: next-version: description: Semver next version, with leading v diff --git a/src/app/generate/generate.go b/src/app/generate/generate.go index 72914210..d743be5e 100644 --- a/src/app/generate/generate.go +++ b/src/app/generate/generate.go @@ -107,7 +107,7 @@ var Cmd = &cli.Command{ Name: exitCodeFlag, EnvVars: common.EnvFor(exitCodeFlag), Usage: "Exit code if generated changelog yaml is empty", - Value: 1, + Value: 0, }, }, Action: Generate, @@ -119,7 +119,10 @@ type appendDepSrc func([]changelog.Source, git.TagsVersionGetter, git.CommitsGet // //nolint:gocyclo,cyclop func Generate(cCtx *cli.Context) error { - gh := gha.NewFromCli(cCtx) + gh, err := gha.NewFromCli(cCtx) + if err != nil { + return fmt.Errorf("creating github client: %w", err) + } yamlPath := cCtx.String(common.YAMLFlag) chFile, err := os.Create(yamlPath) @@ -246,12 +249,7 @@ func tagVersionGetter(cCtx *cli.Context) (*git.TagsSource, error) { versionOpts = append(versionOpts, git.TagSourceReplacing(matching, "")) } - tvsrc := git.NewTagsSource(src, versionOpts...) - if err != nil { - return nil, fmt.Errorf("creating version source from git tag source: %w", err) - } - - return tvsrc, nil + return git.NewTagsSource(src, versionOpts...), nil } func sanitizeValue(in []string) []string { diff --git a/src/app/generate/generate_test.go b/src/app/generate/generate_test.go index 147f435a..7ad51c81 100644 --- a/src/app/generate/generate_test.go +++ b/src/app/generate/generate_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/newrelic/release-toolkit/internal/testutil" "github.com/newrelic/release-toolkit/src/app" "github.com/newrelic/release-toolkit/src/git" ) @@ -37,18 +38,18 @@ This is a release note //nolint:funlen,paralleltest,maintidx func TestGenerate(t *testing.T) { for _, tc := range []struct { - name string - commits []string - author string - md string - expected string - outputExpected string - args string - preCmdArgs string + name string + commits []string + author string + md string + expected string + expectedStdOutput string + expectedGHAOutput string + args string + preCmdArgs string }{ { name: "Empty_Changelog_gha", - args: "--exit-code=0", preCmdArgs: "--gha=1", md: strings.TrimSpace(` # Changelog @@ -61,7 +62,8 @@ This is based on blah blah blah ### Enhancements - This is in the past and should not be included `), - outputExpected: "::set-output name=empty-changelog::true\n", + expectedStdOutput: "", + expectedGHAOutput: "empty-changelog=true\n", expected: strings.TrimSpace(` notes: "" changes: [] @@ -427,6 +429,7 @@ dependencies: } { //nolint:paralleltest t.Run(tc.name, func(t *testing.T) { + ghaOutput := testutil.NewGithubOutputWriter(t) tDir := repoWithCommits(t, tc.author, tc.commits...) tc.expected = calculateHashes(t, tDir, tc.expected) @@ -460,8 +463,11 @@ dependencies: if diff := cmp.Diff(tc.expected, string(yaml)); diff != "" { t.Fatalf("Output YAML is not as expected:\n%s", diff) } - if actual := buf.String(); actual != tc.outputExpected { - t.Fatalf("Expected %q, app printed: %q", tc.outputExpected, actual) + if actual := buf.String(); actual != tc.expectedStdOutput { + t.Fatalf("Expected %q, app printed: %q", tc.expectedStdOutput, actual) + } + if actual := ghaOutput.Result(t); actual != tc.expectedGHAOutput { + t.Fatalf("Expected %q, GHA output: %q", tc.expectedStdOutput, actual) } }) } diff --git a/src/app/gha/gha.go b/src/app/gha/gha.go index 112bc045..27b32265 100644 --- a/src/app/gha/gha.go +++ b/src/app/gha/gha.go @@ -3,13 +3,22 @@ package gha import ( + "errors" "fmt" "io" + "os" + "sync" "github.com/newrelic/release-toolkit/src/app/common" "github.com/urfave/cli/v2" ) +var ErrEmptyFileName = errors.New("filename is an empty string") + +const ( + GithubOutput = "GITHUB_OUTPUT" +) + // New creates a Github object that will print commands to the specified writer. func New(writer io.Writer) Github { return Github{w: writer} @@ -17,21 +26,35 @@ func New(writer io.Writer) Github { // NewFromCli takes a cli.Context and looks for common.GHAFlag on it. If it is set, it returns a Github object that // writes to the app's Writer. If it is not, it returns an empty Github object that does not write anything. -func NewFromCli(cCtx *cli.Context) Github { - if cCtx.Bool(common.GHAFlag) { - return New(cCtx.App.Writer) +func NewFromCli(cCtx *cli.Context) (Github, error) { + if !cCtx.Bool(common.GHAFlag) { + return New(io.Discard), nil + } + + filename := os.Getenv(GithubOutput) + + if filename == "" { + return Github{}, fmt.Errorf("invalid output file: %w", ErrEmptyFileName) + } + + file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) //nolint:mnd,magicnumber + if err != nil { + return Github{}, fmt.Errorf("invalid output file: %w", err) } - return New(io.Discard) + return New(file), nil } // Github is an object that output workflow commands. type Github struct { - w io.Writer + w io.Writer + mu sync.Mutex } // SetOutput outputs the `set-output` command. -// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter -func (g Github) SetOutput(name string, value interface{}) { - _, _ = fmt.Fprintf(g.w, "::set-output name=%s::%v\n", name, value) +// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-output-parameter +func (g *Github) SetOutput(name string, value interface{}) { + g.mu.Lock() + _, _ = fmt.Fprintf(g.w, "%s=%v\n", name, value) + g.mu.Unlock() } diff --git a/src/app/gha/gha_test.go b/src/app/gha/gha_test.go new file mode 100644 index 00000000..6e05a0a0 --- /dev/null +++ b/src/app/gha/gha_test.go @@ -0,0 +1,72 @@ +package gha_test + +import ( + "strings" + "sync" + "testing" + + "github.com/newrelic/release-toolkit/internal/testutil" + "github.com/newrelic/release-toolkit/src/app/gha" +) + +//nolint:paralleltest +func TestGHA_FileIsEmptyByDefault(t *testing.T) { + ghaOutput := testutil.NewGithubOutputWriter(t) + if actual := ghaOutput.Result(t); actual != "" { + t.Fatalf("Expected GHA output is empty") + } +} + +func TestGHA_OutputsAreAppended(t *testing.T) { + t.Parallel() + + buf := &strings.Builder{} + buf.WriteString("not-empty=true\nanother-line=true\n") + + gha := gha.New(buf) + + gha.SetOutput("test", 1) + gha.SetOutput("test", "out") + + expected := strings.TrimSpace(` +not-empty=true +another-line=true +test=1 +test=out + `) + "\n" + + if actual := buf.String(); actual != expected { + t.Fatalf("Expected:\n%s\n\ngot:\n%s", expected, actual) + } +} + +func TestGHA_LockWritesAndDoesNotMangleOutput(t *testing.T) { + t.Parallel() + + buf := &strings.Builder{} + wg := sync.WaitGroup{} + + gha := gha.New(buf) + + for range 5 { + wg.Add(1) + go func() { + gha.SetOutput("test", 1) + wg.Done() + }() + } + + expected := strings.TrimSpace(` +test=1 +test=1 +test=1 +test=1 +test=1 + `) + "\n" + + wg.Wait() + + if actual := buf.String(); actual != expected { + t.Fatalf("Expected:\n%s\n\ngot:\n%s", expected, actual) + } +} diff --git a/src/app/isempty/isempty.go b/src/app/isempty/isempty.go index 00064465..fc806fa5 100644 --- a/src/app/isempty/isempty.go +++ b/src/app/isempty/isempty.go @@ -33,7 +33,10 @@ var Cmd = &cli.Command{ // IsEmpty is a command function which loads a changelog.yaml file, and prints to stdout whether it is empty or not. func IsEmpty(cCtx *cli.Context) error { - gh := gha.NewFromCli(cCtx) + gh, err := gha.NewFromCli(cCtx) + if err != nil { + return fmt.Errorf("creating github client: %w", err) + } chPath := cCtx.String(common.YAMLFlag) chFile, err := os.Open(chPath) diff --git a/src/app/isempty/isempty_test.go b/src/app/isempty/isempty_test.go index 012cb64d..94a98a8b 100644 --- a/src/app/isempty/isempty_test.go +++ b/src/app/isempty/isempty_test.go @@ -2,6 +2,7 @@ package isempty_test import ( "fmt" + "io" "os" "path" "strings" @@ -9,7 +10,9 @@ import ( "github.com/urfave/cli/v2" + "github.com/newrelic/release-toolkit/internal/testutil" "github.com/newrelic/release-toolkit/src/app" + "github.com/newrelic/release-toolkit/src/app/gha" ) //nolint:paralleltest,gocyclo,cyclop @@ -32,24 +35,27 @@ changes: [] `) for _, tc := range []struct { - cmd string - expected string - errExpected bool + cmd string + expectedStdOutput string + expectedGHAOutput string + errExpected bool }{ { - cmd: fmt.Sprintf("rt -yaml %s is-empty", filepath), - expected: "true\n", - errExpected: false, + cmd: fmt.Sprintf("rt -yaml %s is-empty", filepath), + expectedStdOutput: "true\n", + errExpected: false, }, { - cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-empty", filepath), - expected: "true\n::set-output name=is-empty::true\n", - errExpected: false, + cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-empty", filepath), + expectedStdOutput: "true\n", + expectedGHAOutput: "is-empty=true\n", + errExpected: false, }, { - cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-empty -fail", filepath), - expected: "true\n::set-output name=is-empty::true\n", - errExpected: true, + cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-empty -fail", filepath), + expectedStdOutput: "true\n", + expectedGHAOutput: "is-empty=true\n", + errExpected: true, }, } { var errValue int @@ -57,6 +63,14 @@ changes: [] errValue = code } + ghaOutputFileName := path.Join(t.TempDir(), "temporary_github_output_file") + t.Setenv(gha.GithubOutput, ghaOutputFileName) + + ghaOutputFile, err := os.Create(ghaOutputFileName) + if err != nil { + t.Fatalf("Error creating temporary GHA output file for test: %v", err) + } + buf.Reset() err = app.Run(strings.Fields(tc.cmd)) if err != nil && !tc.errExpected { @@ -66,8 +80,8 @@ changes: [] t.Fatalf("An error was expected running app: %v", err) } - if actual := buf.String(); actual != tc.expected { - t.Fatalf("Expected %q, app printed: %q", tc.expected, actual) + if actual := buf.String(); actual != tc.expectedStdOutput { + t.Fatalf("Expected %q, app printed: %q", tc.expectedStdOutput, actual) } if errValue != 1 && tc.errExpected { @@ -77,6 +91,14 @@ changes: [] if errValue == 1 && !tc.errExpected { t.Fatalf("An exit code 1 was not expected") } + + actual, err := io.ReadAll(ghaOutputFile) + if err != nil { + t.Fatalf("Unable to read temporary GHA output file: %v", err) + } + if string(actual) != tc.expectedGHAOutput { + t.Fatalf("Expected %q, GHA output: %q", tc.expectedStdOutput, actual) + } } } @@ -101,16 +123,18 @@ changes: `) for _, tc := range []struct { - cmd string - expected string + cmd string + expectedStdOutput string + expectedGHAOutput string }{ { - cmd: fmt.Sprintf("rt -yaml %s is-empty -fail", filepath), - expected: "false\n", + cmd: fmt.Sprintf("rt -yaml %s is-empty -fail", filepath), + expectedStdOutput: "false\n", }, { - cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-empty -fail", filepath), - expected: "false\n::set-output name=is-empty::false\n", + cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-empty -fail", filepath), + expectedStdOutput: "false\n", + expectedGHAOutput: "is-empty=false\n", }, } { var errValue int @@ -118,14 +142,19 @@ changes: errValue = code } + ghaOutput := testutil.NewGithubOutputWriter(t) + buf.Reset() err = app.Run(strings.Fields(tc.cmd)) if err != nil { t.Fatalf("Error running app: %v", err) } - if actual := buf.String(); actual != tc.expected { - t.Fatalf("Expected %q, app printed: %q", tc.expected, actual) + if actual := buf.String(); actual != tc.expectedStdOutput { + t.Fatalf("Expected %q, app printed: %q", tc.expectedStdOutput, actual) + } + if actual := ghaOutput.Result(t); actual != tc.expectedGHAOutput { + t.Fatalf("Expected %q, GHA output: %q", tc.expectedStdOutput, actual) } if errValue != 0 { diff --git a/src/app/isheld/isheld.go b/src/app/isheld/isheld.go index c1cc1956..76f0b8f8 100644 --- a/src/app/isheld/isheld.go +++ b/src/app/isheld/isheld.go @@ -35,7 +35,10 @@ var Cmd = &cli.Command{ // IsHeld is a command function which loads a changelog.yaml file from this, and prints to stdout whether it has the // Held flag set to true. func IsHeld(cCtx *cli.Context) error { - gh := gha.NewFromCli(cCtx) + gh, err := gha.NewFromCli(cCtx) + if err != nil { + return fmt.Errorf("creating github client: %w", err) + } chPath := cCtx.String(common.YAMLFlag) chFile, err := os.Open(chPath) diff --git a/src/app/isheld/isheld_test.go b/src/app/isheld/isheld_test.go index 5d2839dd..135689fc 100644 --- a/src/app/isheld/isheld_test.go +++ b/src/app/isheld/isheld_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/newrelic/release-toolkit/internal/testutil" "github.com/newrelic/release-toolkit/src/app" ) @@ -32,26 +33,32 @@ changes: `) for _, tc := range []struct { - cmd string - expected string + cmd string + expectedStdOutput string + expectedGHAOutput string }{ { - cmd: fmt.Sprintf("rt -yaml %s is-held", filepath), - expected: "true\n", + cmd: fmt.Sprintf("rt -yaml %s is-held", filepath), + expectedStdOutput: "true\n", }, { - cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-held", filepath), - expected: "true\n::set-output name=is-held::true\n", + cmd: fmt.Sprintf("rt -gha=1 -yaml %s is-held", filepath), + expectedStdOutput: "true\n", + expectedGHAOutput: "is-held=true\n", }, } { + ghaOutput := testutil.NewGithubOutputWriter(t) buf.Reset() err = app.Run(strings.Fields(tc.cmd)) if err != nil { t.Fatalf("Error running app: %v", err) } - if actual := buf.String(); actual != tc.expected { - t.Fatalf("Expected %q, app printed: %q", tc.expected, actual) + if actual := buf.String(); actual != tc.expectedStdOutput { + t.Fatalf("Expected %q, app printed: %q", tc.expectedStdOutput, actual) + } + if actual := ghaOutput.Result(t); actual != tc.expectedGHAOutput { + t.Fatalf("Expected %q, GHA output: %q", tc.expectedStdOutput, actual) } } } diff --git a/src/app/nextversion/nextversion.go b/src/app/nextversion/nextversion.go index fdcb7536..0a96375c 100644 --- a/src/app/nextversion/nextversion.go +++ b/src/app/nextversion/nextversion.go @@ -94,7 +94,7 @@ next-version will exit with an error if no previous versions are found in the gi EnvVars: common.EnvFor(failFlag), Usage: "If set, command will exit with a code of 1 if no new version bump is produced. If not set," + "the current version will be returned.", - Value: false, + Value: true, }, }, Action: NextVersion, @@ -105,7 +105,10 @@ next-version will exit with an error if no previous versions are found in the gi // //nolint:gocyclo,cyclop func NextVersion(cCtx *cli.Context) error { - gh := gha.NewFromCli(cCtx) + gh, err := gha.NewFromCli(cCtx) + if err != nil { + return fmt.Errorf("creating github client: %w", err) + } nextOverride, err := parseNextFlag(cCtx.String(nextFlag)) if err != nil { @@ -166,10 +169,11 @@ func NextVersion(cCtx *cli.Context) error { case nextOverride == nil && next != nil: // If we don't have an override, the bumper did not bump anything, and the user has set `--fail`, then we should error out. if errors.Is(err, bumper.ErrNoNewVersion) { - log.Warnf("None of the changelog entries produced a version bump, returning current version") - if cCtx.Bool("fail") { - return fmt.Errorf("failing by user request: %w", err) + if cCtx.Bool(failFlag) { + return fmt.Errorf("none of the changelog entries produced a version bump: %w", err) } + + log.Warnf("None of the changelog entries produced a version bump, returning current version") } case nextOverride == nil && next == nil: diff --git a/src/app/nextversion/nextversion_test.go b/src/app/nextversion/nextversion_test.go index 572b1ae5..f70f0b88 100644 --- a/src/app/nextversion/nextversion_test.go +++ b/src/app/nextversion/nextversion_test.go @@ -9,24 +9,27 @@ import ( "strings" "testing" + "github.com/newrelic/release-toolkit/internal/testutil" "github.com/newrelic/release-toolkit/src/app" "github.com/newrelic/release-toolkit/src/bump" + "github.com/newrelic/release-toolkit/src/bumper" ) //nolint:paralleltest, funlen // urfave/cli cannot be tested concurrently. func TestNextVersion_Without_Repo(t *testing.T) { for _, tc := range []struct { - name string - yaml string - expected string - errorExpected error - args string - globalargs string + name string + yaml string + expectedStdOutput string + expectedGHAOutput string + errorExpected error + args string + globalargs string }{ { - name: "Overrides_Next_And_Current", - args: "-next v0.0.1 -current v1.2.3", - expected: "v0.0.1", + name: "Overrides_Next_And_Current", + args: "-next v0.0.1 -current v1.2.3", + expectedStdOutput: "v0.0.1", yaml: strings.TrimSpace(` notes: |- ### Important announcement (note) @@ -46,9 +49,9 @@ dependencies: `), }, { - name: "Bumps_Patch", - args: "-current v1.2.3", - expected: "v1.2.4", + name: "Bumps_Patch", + args: "-current v1.2.3", + expectedStdOutput: "v1.2.4", yaml: strings.TrimSpace(` changes: - type: bugfix @@ -56,9 +59,9 @@ changes: `), }, { - name: "Bumps_Minor", - args: "-current v1.2.3", - expected: "v1.3.0", + name: "Bumps_Minor", + args: "-current v1.2.3", + expectedStdOutput: "v1.3.0", yaml: strings.TrimSpace(` changes: - type: enhancement @@ -66,9 +69,9 @@ changes: `), }, { - name: "Bumps_Major", - args: "-current v1.2.3", - expected: "v2.0.0", + name: "Bumps_Major", + args: "-current v1.2.3", + expectedStdOutput: "v2.0.0", yaml: strings.TrimSpace(` changes: - type: breaking @@ -76,10 +79,11 @@ changes: `), }, { - name: "Bumps_Major_GHA", - globalargs: "-gha=true", - args: "-current v1.2.3", - expected: "v2.0.0\n::set-output name=next-version::v2.0.0\n::set-output name=next-version-major::v2\n::set-output name=next-version-major-minor::v2.0", + name: "Bumps_Major_GHA", + globalargs: "-gha=true", + args: "-current v1.2.3", + expectedStdOutput: "v2.0.0", + expectedGHAOutput: "next-version=v2.0.0\nnext-version-major=v2\nnext-version-major-minor=v2.0\n", yaml: strings.TrimSpace(` changes: - type: breaking @@ -87,9 +91,17 @@ changes: `), }, { - name: "No_Bump", - args: "-current v1.2.3", - expected: "v1.2.3", + name: "No_Bump_without_failing", + args: "-current v1.2.3 -fail=false", + expectedStdOutput: "v1.2.3", + yaml: strings.TrimSpace(` +changes: [] + `), + }, + { + name: "No_Bump_fails_by_default", + args: "-current v1.2.3", + errorExpected: bumper.ErrNoNewVersion, yaml: strings.TrimSpace(` changes: [] `), @@ -99,6 +111,7 @@ changes: [] //nolint:paralleltest // urfave/cli cannot be tested concurrently. t.Run(tc.name, func(t *testing.T) { tDir := t.TempDir() + ghaOutput := testutil.NewGithubOutputWriter(t) app := app.App() @@ -118,9 +131,11 @@ changes: [] t.Fatalf("Expected error %v, got %v", tc.errorExpected, err) } - actual := buf.String() - if tc.expected != "" && actual != tc.expected+"\n" { - t.Fatalf("Expected %q, got %q", tc.expected, actual) + if actual := buf.String(); tc.expectedStdOutput != "" && actual != tc.expectedStdOutput+"\n" { + t.Fatalf("Expected %q, App printed: %q", tc.expectedStdOutput, actual) + } + if actual := ghaOutput.Result(t); actual != tc.expectedGHAOutput { + t.Fatalf("Expected %q, GHA output: %q", tc.expectedStdOutput, actual) } }) } diff --git a/src/app/validate/validate.go b/src/app/validate/validate.go index 80b3860a..7db006bf 100644 --- a/src/app/validate/validate.go +++ b/src/app/validate/validate.go @@ -42,7 +42,10 @@ var Cmd = &cli.Command{ // Validate is a command function which loads a changelog.md file, and prints to stderr // all the errors found. func Validate(cCtx *cli.Context) error { - gh := gha.NewFromCli(cCtx) + gh, err := gha.NewFromCli(cCtx) + if err != nil { + return fmt.Errorf("creating github client: %w", err) + } mdPath := cCtx.String(markdownPathFlag) chFile, err := os.Open(mdPath) diff --git a/src/app/validate/validate_test.go b/src/app/validate/validate_test.go index af5e1706..268fc931 100644 --- a/src/app/validate/validate_test.go +++ b/src/app/validate/validate_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/newrelic/release-toolkit/internal/testutil" "github.com/newrelic/release-toolkit/src/app" ) @@ -74,7 +75,7 @@ Support has been removed "Important announcement (note)" header found with empty content "Breaking" header must contain only an itemized list `, "\n"), - expectedGha: "::set-output name=valid::false\n", + expectedGha: "valid=false\n", }, { name: "Valid_Changelog", @@ -126,7 +127,7 @@ This is a release note `), args: "--exit-code=0", expectedErr: "", - expectedGha: "::set-output name=valid::true\n", + expectedGha: "valid=true\n", }, { name: "Invalid_Changelog_Only_Notes", @@ -154,12 +155,11 @@ unreleased changelog can't only contain notes //nolint:paralleltest // urfave/cli cannot be tested concurrently. t.Run(tc.name, func(t *testing.T) { tDir := t.TempDir() + ghaOutput := testutil.NewGithubOutputWriter(t) app := app.App() bufErr := &strings.Builder{} - buf := &strings.Builder{} app.ErrWriter = bufErr - app.Writer = buf mdPath := path.Join(tDir, "CHANGELOG.md") mdFile, err := os.Create(mdPath) @@ -178,8 +178,7 @@ unreleased changelog can't only contain notes if actual := bufErr.String(); actual != tc.expectedErr { t.Fatalf("Expected:\n%s\n\napp printed:\n%s", tc.expectedErr, actual) } - - if actual := buf.String(); actual != tc.expectedGha { + if actual := ghaOutput.Result(t); actual != tc.expectedGha { t.Fatalf("Expected:\n%s\n\napp printed:\n%s", tc.expectedGha, actual) } })