diff --git a/.github/workflows/create_pr_for_changelog.yml b/.github/workflows/create_pr_for_changelog.yml new file mode 100644 index 000000000..645d9a918 --- /dev/null +++ b/.github/workflows/create_pr_for_changelog.yml @@ -0,0 +1,53 @@ +name: Generate changelog PR + +on: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Generate the full changelog + uses: orhun/git-cliff-action@v4 + id: git_cliff + with: + config: cliff.toml + args: --verbose --exclude-path "data/" --bump + env: + OUTPUT: CHANGELOG.md + + - name: Generate latest changes + uses: orhun/git-cliff-action@v4 + id: git_cliff_latest + with: + config: cliff.toml + args: --verbose --latest --strip header --exclude-path "data/" --bump --unreleased + + - name: Create Pull Request + if: steps.git_cliff.outputs.version != 'null' + uses: peter-evans/create-pull-request@v7 + with: + add-paths: | + CHANGELOG.md + base: master + commit-message: "chore: update CHANGELOG.md for ${{ steps.git_cliff.outputs.version }}" + signoff: true + sign-commits: true + branch: chore/next-release-changelog + delete-branch: true + title: "chore(release): release ${{ steps.git_cliff.outputs.version }}" + body: ${{ steps.git_cliff_latest.outputs.content }} + labels: | + pending-release + automated diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml new file mode 100644 index 000000000..73b286b9f --- /dev/null +++ b/.github/workflows/create_release.yml @@ -0,0 +1,103 @@ +name: Create tag and release + +on: + pull_request: + types: [closed] + +permissions: + contents: write + pull-requests: write + +env: + ECOBALYSE_DATA_DIR: ./ecobalyse-private + +jobs: + create_tag_and_release: + # The tag and the release should be created only when the automated PR created by `create_pr_for_changelog` is merged + # Or to test it for now, by triggering a workflow dispatch by hand + if: (github.event.pull_request.merged == true && startsWith(github.event.pull_request.title, 'chore(release)') && contains(github.event.pull_request.labels.*.name, 'automated') && contains(github.event.pull_request.labels.*.name, 'pending-release')) + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get latest version + uses: orhun/git-cliff-action@v4 + id: git_cliff + with: + config: cliff.toml + args: -vv --latest --strip header --exclude-path "data/" --bump --unreleased + + - name: Set up Git + run: | + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + - name: Create and push tag + # If something went wrong when getting the latest version from `git-cliff` + # don't create a messy tag + if: steps.git_cliff.outputs.version != 'null' + id: tag_creation + run: | + git tag -a "${{ steps.git_cliff.outputs.version }}" -m "Release ${{ steps.git_cliff.outputs.version }}" + git push origin "${{ steps.git_cliff.outputs.version }}" + echo "tag_created=true" >> "$GITHUB_OUTPUT" + echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + if: steps.tag_creation.outputs.tag_created + + - name: Install Node dependencies + if: steps.tag_creation.outputs.tag_created + run: npm ci --prefer-offline --no-audit + + - name: Clone the detailed impacts + if: steps.tag_creation.outputs.tag_created + run: | + eval `ssh-agent -s` + ssh-add - <<< '${{ secrets.PRIVATE_SSH_KEY }}' + git clone git@github.com:MTES-MCT/ecobalyse-private.git + + - name: Build app + if: steps.tag_creation.outputs.tag_created + env: + # Specify the created SHA to correctly update version.json + SOURCE_VERSION: ${{ steps.git_cliff.outputs.sha }} + TAG: ${{ steps.git_cliff.outputs.version }} + run: | + npm run build:standalone-app + + - name: Encrypt the impacts files + if: steps.tag_creation.outputs.tag_created + env: + ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} + run : | + # We include the encrypted detailed processes with the dist + # so that people with the encryption key could later on use the app with the exact + # files it was using on production + npm run encrypt $ECOBALYSE_DATA_DIR/data/textile/processes_impacts.json dist/processes_impacts_textile.json.enc + npm run encrypt $ECOBALYSE_DATA_DIR/data/food/processes_impacts.json dist/processes_impacts_food.json.enc + + - name: Generate dist archive + if: steps.tag_creation.outputs.tag_created + run: | + tar czvf ${{ steps.git_cliff.outputs.version }}-dist.tar.gz dist + + - name: Create release + if: steps.tag_creation.outputs.tag_created + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.git_cliff.outputs.version }} + body: ${{ steps.git_cliff.outputs.content }} + files: ${{ steps.git_cliff.outputs.version }}-dist.tar.gz + generate_release_notes: false + make_latest: true diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index 7c2c96024..000000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: release-please - -on: - push: - branches: - - master - -permissions: - contents: write - pull-requests: write - -env: - ECOBALYSE_DATA_DIR: ./ecobalyse-private - -jobs: - release-please: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - steps: - - uses: googleapis/release-please-action@v4 - id: release - with: - token: ${{ secrets.GITHUB_TOKEN }} - release-type: node - - # The logic below handles the static assets publication - - uses: actions/checkout@v4 - if: ${{ steps.release.outputs.release_created }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - if: ${{ steps.release.outputs.release_created }} - - - name: Install Node dependencies - if: ${{ steps.release.outputs.release_created }} - run: npm ci --prefer-offline --no-audit - - - name: Clone the detailed impacts - if: ${{ steps.release.outputs.release_created }} - run: | - eval `ssh-agent -s` - ssh-add - <<< '${{ secrets.PRIVATE_SSH_KEY }}' - git clone git@github.com:MTES-MCT/ecobalyse-private.git - - - name: Build app - if: ${{ steps.release.outputs.release_created }} - env: - # Specify the created SHA to correctly update version.json - SOURCE_VERSION: ${{ steps.release.outputs.sha }} - TAG: ${{ steps.release.outputs.tag_name }} - run: | - npm run build:standalone-app - - - name: Encrypt the impacts files - if: ${{ steps.release.outputs.release_created }} - env: - ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }} - run : | - # We include the encrypted detailed processes with the dist - # so that people with the encryption key could later on use the app with the exact - # files it was using on production - npm run encrypt $ECOBALYSE_DATA_DIR/data/textile/processes_impacts.json dist/processes_impacts_textile.json.enc - npm run encrypt $ECOBALYSE_DATA_DIR/data/food/processes_impacts.json dist/processes_impacts_food.json.enc - - - name: Generate dist archive - if: ${{ steps.release.outputs.release_created }} - run: | - tar czvf ${{ steps.release.outputs.tag_name }}-dist.tar.gz dist - - - name: Archive production artifacts - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist - if: ${{ steps.release.outputs.release_created }} - - - name: Upload Release Artifact - if: ${{ steps.release.outputs.release_created }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh release upload ${{ steps.release.outputs.tag_name }} ${{ steps.release.outputs.tag_name }}-dist.tar.gz diff --git a/bin/download_github_releases.py b/bin/download_github_releases.py index 333a8633a..3a9aa2b6e 100755 --- a/bin/download_github_releases.py +++ b/bin/download_github_releases.py @@ -81,6 +81,9 @@ def download_file(url, destination_directory=None): for asset in release.assets: if "-dist.tar.gz" in asset.browser_download_url: + logger.info( + f"Downloading {asset.browser_download_url} to {args.destination_directory}." + ) file_path = download_file( asset.browser_download_url, args.destination_directory ) diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 000000000..7b544e2ea --- /dev/null +++ b/cliff.toml @@ -0,0 +1,89 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +# template for the changelog header +header = """ +# Changelog\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% if version %}\ + {% if previous.version %} + ## [{{ version | trim_start_matches(pat="v") }}](https://github.com/MTES-MCT/ecobalyse/compare/{{ previous.version }}..{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }}) + + {% else %} + ## {{ version | trim_start_matches(pat="v") }} ({{ timestamp | date(format="%Y-%m-%d") }}) + {% endif %} +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | upper_first }}\ + {% endfor %} +{% endfor %}\n +""" +# template for the changelog footer +footer = """ + +""" +# remove the leading and trailing s +trim = true +# postprocessors +postprocessors = [ + { pattern = '', replace = "https://github.com/MTES-MCT/ecobalyse" }, # replace repository URL +] +# render body even when there are no releases to process +# render_always = true +# output file path +# output = "test.md" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # Replace issue numbers + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"}, + # Check spelling of the commit with https://github.com/crate-ci/typos + # If the spelling is incorrect, it will be automatically fixed. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "๐Ÿš€ Features" }, + { message = "^fix", group = "๐Ÿชฒ Bug Fixes" }, + { message = "^doc", group = "๐Ÿ“š Documentation" }, + { message = "^perf", group = "โšก Performance" }, + { message = "^refactor", group = "๐Ÿšœ Refactor" }, + { message = "^style", group = "๐ŸŽจ Styling" }, + { message = "^test", group = "๐Ÿงช Testing" }, + { message = "^chore\\(release\\):", skip = true }, + { message = "^chore\\(master\\): release", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^chore\\(Snyk\\)", skip = true }, + { message = "^chore|^ci", group = "โš™๏ธ Miscellaneous Tasks" }, + { body = ".*security", group = "๐Ÿ›ก๏ธ Security" }, + { message = "^revert", group = "โ—€๏ธ Revert" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = false +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" diff --git a/package.json b/package.json index 17a628a57..d6847c2a1 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ "dependencies": { "@sentry/browser": "^8.28.0", "@sentry/node": "^8.29.0", - "@sentry/tracing": "^7.119.0", "@sentry/profiling-node": "^8.29.0", + "@sentry/tracing": "^7.119.0", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.21.0", @@ -65,25 +65,25 @@ }, "devDependencies": { "@apidevtools/swagger-cli": "^4.0.4", + "@parcel/transformer-elm": "^2.12.0", + "@parcel/transformer-image": "^2.12.0", + "@parcel/transformer-sass": "^2.12.0", + "bootstrap": "^5.3.3", "concurrently": "^8.2.2", + "elm": "^0.19.1-6", "elm-format": "^0.8.7", "elm-json": "^0.2.13", "elm-review": "^2.12.0", "elm-test": "0.19.1-revision12", + "highcharts": "^11.4.8", "jest": "^29.7.0", "nodemon": "^3.1.4", "npm-check-updates": "^17.1.0", + "parcel": "^2.12.0", "prettier": "^3.3.3", "process": "^0.11.10", "rimraf": "^6.0.1", - "supertest": "^7.0.0", - "parcel": "^2.12.0", - "@parcel/transformer-elm": "^2.12.0", - "@parcel/transformer-image": "^2.12.0", - "@parcel/transformer-sass": "^2.12.0", - "highcharts": "^11.4.8", - "bootstrap": "^5.3.3", - "elm": "^0.19.1-6" + "supertest": "^7.0.0" }, "cacheDirectories": [ "node_modules",