mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 16:41:45 +03:00
Apply unified prettier style to engine codebase (#3145)
This commit is contained in:
parent
83e35751f4
commit
8fc51bfe44
3
.github/settings.yml
vendored
3
.github/settings.yml
vendored
@ -81,8 +81,7 @@ labels:
|
|||||||
description: A change that will break a public API or user-facing behaviour
|
description: A change that will break a public API or user-facing behaviour
|
||||||
- name: "Change: Non-Breaking"
|
- name: "Change: Non-Breaking"
|
||||||
color: "#ffdce5"
|
color: "#ffdce5"
|
||||||
description:
|
description: A change that will not break a public API or user-facing behaviour
|
||||||
A change that will not break a public API or user-facing behaviour
|
|
||||||
|
|
||||||
- name: "Difficulty: Beginner"
|
- name: "Difficulty: Beginner"
|
||||||
color: "#d1e9c4"
|
color: "#d1e9c4"
|
||||||
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@ -26,7 +26,7 @@ jobs:
|
|||||||
- name: Install Prettier
|
- name: Install Prettier
|
||||||
run: npm install
|
run: npm install
|
||||||
- name: Check Docs
|
- name: Check Docs
|
||||||
run: npx prettier --check .
|
run: npx prettier --version && npx prettier --check .
|
||||||
|
|
||||||
changelog-check:
|
changelog-check:
|
||||||
name: Changelog Check
|
name: Changelog Check
|
||||||
|
10
.github/workflows/gui.yml
vendored
10
.github/workflows/gui.yml
vendored
@ -118,16 +118,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
toolchain: nightly-2021-10-29
|
toolchain: nightly-2021-10-29
|
||||||
override: true
|
override: true
|
||||||
- name: Install Prettier
|
|
||||||
run: npm install --save-dev --save-exact prettier
|
|
||||||
- name: Install Clippy
|
- name: Install Clippy
|
||||||
run: rustup component add clippy
|
run: rustup component add clippy
|
||||||
- name: Install Clippy
|
- name: Install Clippy
|
||||||
run: rustup component add rustfmt
|
run: rustup component add rustfmt
|
||||||
- name: Lint Markdown sources
|
|
||||||
run: npx prettier --check '*.md'
|
|
||||||
- name: Lint JavaScript sources
|
|
||||||
run: npx prettier --check 'src/**/*.js'
|
|
||||||
- name: Lint Rust sources
|
- name: Lint Rust sources
|
||||||
run: node ./run lint --skip-version-validation
|
run: node ./run lint --skip-version-validation
|
||||||
test:
|
test:
|
||||||
@ -462,10 +456,6 @@ jobs:
|
|||||||
if [[ ${{ steps.checkCurrentReleaseTag.outputs.exists }} == true ]];
|
if [[ ${{ steps.checkCurrentReleaseTag.outputs.exists }} == true ]];
|
||||||
then exit 1; fi
|
then exit 1; fi
|
||||||
if: github.base_ref == 'unstable' || github.base_ref == 'stable'
|
if: github.base_ref == 'unstable' || github.base_ref == 'stable'
|
||||||
- name: Install Prettier
|
|
||||||
run: npm install --save-dev --save-exact prettier
|
|
||||||
- name: Pretty print changelog.
|
|
||||||
run: npx prettier --prose-wrap never CHANGELOG.md --write
|
|
||||||
- name: Upload GitHub Release
|
- name: Upload GitHub Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
env:
|
env:
|
||||||
|
39
.github/workflows/nightly.yml
vendored
39
.github/workflows/nightly.yml
vendored
@ -29,8 +29,7 @@ jobs:
|
|||||||
name: Nightly Preflight Check
|
name: Nightly Preflight Check
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
if:
|
if: "${{ github.event_name == 'schedule' ||
|
||||||
"${{ github.event_name == 'schedule' ||
|
|
||||||
contains(github.event.head_commit.message,'[release: nightly]') }}"
|
contains(github.event.head_commit.message,'[release: nightly]') }}"
|
||||||
outputs:
|
outputs:
|
||||||
proceed: ${{ steps.preparations.outputs.proceed }}
|
proceed: ${{ steps.preparations.outputs.proceed }}
|
||||||
@ -452,8 +451,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name: enso-engine-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
asset_name: enso-engine-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -463,8 +461,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name: enso-engine-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
asset_name: enso-engine-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -474,8 +471,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name: enso-engine-${{ env.DIST_VERSION }}-windows-amd64.zip
|
asset_name: enso-engine-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
@ -486,8 +482,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name: enso-launcher-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
asset_name: enso-launcher-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -497,8 +492,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name: enso-launcher-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
asset_name: enso-launcher-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -508,8 +502,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name: enso-launcher-${{ env.DIST_VERSION }}-windows-amd64.zip
|
asset_name: enso-launcher-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
@ -523,8 +516,7 @@ jobs:
|
|||||||
asset_path:
|
asset_path:
|
||||||
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name:
|
asset_name: enso-project-manager-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
enso-project-manager-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
- name: Publish the Project Manager (MacOS)
|
- name: Publish the Project Manager (MacOS)
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@ -535,8 +527,7 @@ jobs:
|
|||||||
asset_path:
|
asset_path:
|
||||||
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name:
|
asset_name: enso-project-manager-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
enso-project-manager-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
- name: Publish the Project Manager (Windows)
|
- name: Publish the Project Manager (Windows)
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@ -547,8 +538,7 @@ jobs:
|
|||||||
asset_path:
|
asset_path:
|
||||||
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name:
|
asset_name: enso-project-manager-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
enso-project-manager-${{ env.DIST_VERSION }}-windows-amd64.zip
|
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
|
||||||
- name: Publish the Bundle (Linux)
|
- name: Publish the Bundle (Linux)
|
||||||
@ -557,8 +547,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name: enso-bundle-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
asset_name: enso-bundle-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -568,8 +557,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name: enso-bundle-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
asset_name: enso-bundle-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -579,8 +567,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name: enso-bundle-${{ env.DIST_VERSION }}-windows-amd64.zip
|
asset_name: enso-bundle-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
36
.github/workflows/release.yml
vendored
36
.github/workflows/release.yml
vendored
@ -466,8 +466,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name: enso-engine-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
asset_name: enso-engine-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -477,8 +476,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name: enso-engine-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
asset_name: enso-engine-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -488,8 +486,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-engine-${{ env.DIST_VERSION
|
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name: enso-engine-${{ env.DIST_VERSION }}-windows-amd64.zip
|
asset_name: enso-engine-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
@ -500,8 +497,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name: enso-launcher-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
asset_name: enso-launcher-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -511,8 +507,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name: enso-launcher-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
asset_name: enso-launcher-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -522,8 +517,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-launcher-${{ env.DIST_VERSION
|
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name: enso-launcher-${{ env.DIST_VERSION }}-windows-amd64.zip
|
asset_name: enso-launcher-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
@ -537,8 +531,7 @@ jobs:
|
|||||||
asset_path:
|
asset_path:
|
||||||
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name:
|
asset_name: enso-project-manager-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
enso-project-manager-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
- name: Publish the Project Manager (MacOS)
|
- name: Publish the Project Manager (MacOS)
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@ -549,8 +542,7 @@ jobs:
|
|||||||
asset_path:
|
asset_path:
|
||||||
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name:
|
asset_name: enso-project-manager-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
enso-project-manager-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
- name: Publish the Project Manager (Windows)
|
- name: Publish the Project Manager (Windows)
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
@ -561,8 +553,7 @@ jobs:
|
|||||||
asset_path:
|
asset_path:
|
||||||
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
repo/built-distribution/enso-project-manager-${{ env.DIST_VERSION
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name:
|
asset_name: enso-project-manager-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
enso-project-manager-${{ env.DIST_VERSION }}-windows-amd64.zip
|
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
|
||||||
- name: Publish the Bundle (Linux)
|
- name: Publish the Bundle (Linux)
|
||||||
@ -571,8 +562,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
|
||||||
}}-linux-amd64.tar.gz
|
}}-linux-amd64.tar.gz
|
||||||
asset_name: enso-bundle-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
asset_name: enso-bundle-${{ env.DIST_VERSION }}-linux-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -582,8 +572,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
|
||||||
}}-macos-amd64.tar.gz
|
}}-macos-amd64.tar.gz
|
||||||
asset_name: enso-bundle-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
asset_name: enso-bundle-${{ env.DIST_VERSION }}-macos-amd64.tar.gz
|
||||||
asset_content_type: application/x-tar
|
asset_content_type: application/x-tar
|
||||||
@ -593,8 +582,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path:
|
asset_path: repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
||||||
repo/built-distribution/enso-bundle-${{ env.DIST_VERSION
|
|
||||||
}}-windows-amd64.zip
|
}}-windows-amd64.zip
|
||||||
asset_name: enso-bundle-${{ env.DIST_VERSION }}-windows-amd64.zip
|
asset_name: enso-bundle-${{ env.DIST_VERSION }}-windows-amd64.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
3
.github/workflows/rust.yml
vendored
3
.github/workflows/rust.yml
vendored
@ -160,8 +160,7 @@ jobs:
|
|||||||
WASMPACKURL:
|
WASMPACKURL:
|
||||||
https://github.com/rustwasm/wasm-pack/releases/download/v${{
|
https://github.com/rustwasm/wasm-pack/releases/download/v${{
|
||||||
env.wasmpackVersion }}
|
env.wasmpackVersion }}
|
||||||
WASMPACKDIR:
|
WASMPACKDIR: wasm-pack-v${{ env.wasmpackVersion }}-x86_64-unknown-linux-musl
|
||||||
wasm-pack-v${{ env.wasmpackVersion }}-x86_64-unknown-linux-musl
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
curl -L "$WASMPACKURL/$WASMPACKDIR.tar.gz" | tar -xz -C .
|
curl -L "$WASMPACKURL/$WASMPACKDIR.tar.gz" | tar -xz -C .
|
||||||
|
@ -13,5 +13,8 @@ distribution/lib/Standard/Database/*/THIRD-PARTY
|
|||||||
built-distribution/
|
built-distribution/
|
||||||
THIRD-PARTY
|
THIRD-PARTY
|
||||||
|
|
||||||
|
# GUI
|
||||||
gui/dist/
|
gui/dist/
|
||||||
**/scala-parser.js
|
**/scala-parser.js
|
||||||
|
**/package-lock.json
|
||||||
|
**/msdfgen_wasm.js
|
||||||
|
@ -118,11 +118,6 @@ let installNode = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let installPrettier = {
|
|
||||||
name: 'Install Prettier',
|
|
||||||
run: 'npm install --save-dev --save-exact prettier',
|
|
||||||
}
|
|
||||||
|
|
||||||
let installClippy = {
|
let installClippy = {
|
||||||
name: 'Install Clippy',
|
name: 'Install Clippy',
|
||||||
run: 'rustup component add clippy',
|
run: 'rustup component add clippy',
|
||||||
@ -192,16 +187,6 @@ let buildPackage = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let lintMarkdown = {
|
|
||||||
name: 'Lint Markdown sources',
|
|
||||||
run: "npx prettier --check '*.md'",
|
|
||||||
}
|
|
||||||
|
|
||||||
let lintJavaScript = {
|
|
||||||
name: 'Lint JavaScript sources',
|
|
||||||
run: "npx prettier --check 'src/**/*.js'",
|
|
||||||
}
|
|
||||||
|
|
||||||
let lintRust = {
|
let lintRust = {
|
||||||
name: 'Lint Rust sources',
|
name: 'Lint Rust sources',
|
||||||
run: 'node ./run lint --skip-version-validation',
|
run: 'node ./run lint --skip-version-validation',
|
||||||
@ -328,11 +313,6 @@ let assertChangelogWasUpdated = [
|
|||||||
// ======================
|
// ======================
|
||||||
|
|
||||||
let uploadGitHubRelease = [
|
let uploadGitHubRelease = [
|
||||||
installPrettier,
|
|
||||||
{
|
|
||||||
name: `Pretty print changelog.`,
|
|
||||||
run: 'npx prettier --prose-wrap never CHANGELOG.md --write',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: `Upload GitHub Release`,
|
name: `Upload GitHub Release`,
|
||||||
uses: 'softprops/action-gh-release@v1',
|
uses: 'softprops/action-gh-release@v1',
|
||||||
@ -467,11 +447,8 @@ let workflow = {
|
|||||||
installNode,
|
installNode,
|
||||||
installTypeScript,
|
installTypeScript,
|
||||||
installRust,
|
installRust,
|
||||||
installPrettier,
|
|
||||||
installClippy,
|
installClippy,
|
||||||
installFmt,
|
installFmt,
|
||||||
lintMarkdown,
|
|
||||||
lintJavaScript,
|
|
||||||
lintRust,
|
lintRust,
|
||||||
]),
|
]),
|
||||||
test: job_on_linux_cached('test_native', 'Native Tests', [
|
test: job_on_linux_cached('test_native', 'Native Tests', [
|
||||||
|
@ -1,57 +1,53 @@
|
|||||||
import { StaticNavigation } from "components/navigation";
|
import { StaticNavigation } from 'components/navigation'
|
||||||
import {
|
import { Container, ContainerOrScreenIfSmall, RootContainer } from 'components/container'
|
||||||
Container,
|
import { Header } from 'components/header'
|
||||||
ContainerOrScreenIfSmall,
|
import { Chapter } from 'components/chapter'
|
||||||
RootContainer,
|
import { SectionCommunity } from 'components/section-community'
|
||||||
} from "components/container";
|
import { SectionFooter } from 'components/section-footer'
|
||||||
import { Header } from "components/header";
|
import { StickyButtons } from 'components/sticky-buttons'
|
||||||
import { Chapter } from "components/chapter";
|
|
||||||
import { SectionCommunity } from "components/section-community";
|
|
||||||
import { SectionFooter } from "components/section-footer";
|
|
||||||
import { StickyButtons } from "components/sticky-buttons";
|
|
||||||
|
|
||||||
import AtomsIcon from "../../../public/img/icon/atoms.svg";
|
import AtomsIcon from '../../../public/img/icon/atoms.svg'
|
||||||
import MethodsIcon from "../../../public/img/icon/methods.svg";
|
import MethodsIcon from '../../../public/img/icon/methods.svg'
|
||||||
import SubmodulesIcon from "../../../public/img/icon/submodules.svg";
|
import SubmodulesIcon from '../../../public/img/icon/submodules.svg'
|
||||||
|
|
||||||
function Docs() {
|
function Docs() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/*<div className="breadcrumb-panel">*/}
|
{/*<div className="breadcrumb-panel">*/}
|
||||||
{/* <Container>/!*BREADCRUMBS2*!/</Container>*/}
|
{/* <Container>/!*BREADCRUMBS2*!/</Container>*/}
|
||||||
{/*</div>*/}
|
{/*</div>*/}
|
||||||
<Container>
|
<Container>
|
||||||
<div className="root">
|
<div className="root">
|
||||||
<div className="toc">{/*BREADCRUMBS*/}</div>
|
<div className="toc">{/*BREADCRUMBS*/}</div>
|
||||||
{/*PAGE*/}
|
{/*PAGE*/}
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
)
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Main(props) {
|
export default function Main(props) {
|
||||||
return (
|
return (
|
||||||
<RootContainer className="theme-light">
|
<RootContainer className="theme-light">
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<Chapter id="home" noSpacing="true">
|
<Chapter id="home" noSpacing="true">
|
||||||
<div className="bg-lang-bg">
|
<div className="bg-lang-bg">
|
||||||
<StaticNavigation dark="true" />
|
<StaticNavigation dark="true" />
|
||||||
</div>
|
</div>
|
||||||
</Chapter>
|
</Chapter>
|
||||||
<div className="doc">
|
<div className="doc">
|
||||||
<Docs />
|
<Docs />
|
||||||
</div>
|
</div>
|
||||||
<Chapter id="community">
|
<Chapter id="community">
|
||||||
<SectionCommunity />
|
<SectionCommunity />
|
||||||
</Chapter>
|
</Chapter>
|
||||||
|
|
||||||
<StickyButtons />
|
<StickyButtons />
|
||||||
|
|
||||||
<Chapter id="footer">
|
<Chapter id="footer">
|
||||||
<SectionFooter />
|
<SectionFooter />
|
||||||
</Chapter>
|
</Chapter>
|
||||||
</RootContainer>
|
</RootContainer>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "2.0.5"
|
"prettier": "2.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,56 @@
|
|||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
const proc = require("child_process");
|
const proc = require('child_process')
|
||||||
|
|
||||||
const skipChangelogInfix = "[no-changelog]";
|
const skipChangelogInfix = '[no-changelog]'
|
||||||
const changelogPath = process.argv[2];
|
const changelogPath = process.argv[2]
|
||||||
const baseRef = process.argv[3];
|
const baseRef = process.argv[3]
|
||||||
|
|
||||||
/// Runs the git command with the provided arguments.
|
/// Runs the git command with the provided arguments.
|
||||||
function runGit(args) {
|
function runGit(args) {
|
||||||
const result = proc.spawnSync("git", args);
|
const result = proc.spawnSync('git', args)
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
console.log("Cannot access git", result.error);
|
console.log('Cannot access git', result.error)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks if the changelog file was changed in any commits that are part of the
|
/** Checks if the changelog file was changed in any commits that are part of the
|
||||||
* PR.
|
* PR.
|
||||||
*/
|
*/
|
||||||
function wasChangelogModified() {
|
function wasChangelogModified() {
|
||||||
const diffArgs = [
|
const diffArgs = ['--no-pager', 'diff', '--exit-code', baseRef, '--', changelogPath]
|
||||||
"--no-pager",
|
|
||||||
"diff",
|
|
||||||
"--exit-code",
|
|
||||||
baseRef,
|
|
||||||
"--",
|
|
||||||
changelogPath,
|
|
||||||
];
|
|
||||||
|
|
||||||
const result = runGit(diffArgs);
|
const result = runGit(diffArgs)
|
||||||
const exitCode = result.status;
|
const exitCode = result.status
|
||||||
console.log(result.stdout.toString("utf-8"));
|
console.log(result.stdout.toString('utf-8'))
|
||||||
const noDifference = exitCode == 0;
|
const noDifference = exitCode == 0
|
||||||
return !noDifference;
|
return !noDifference
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if any commit has overridden the changelog check.
|
/// Checks if any commit has overridden the changelog check.
|
||||||
function isChangelogSkipped() {
|
function isChangelogSkipped() {
|
||||||
const logArgs = ["--no-pager", "log", "HEAD~3...HEAD", "--pretty=oneline"];
|
const logArgs = ['--no-pager', 'log', 'HEAD~3...HEAD', '--pretty=oneline']
|
||||||
const result = runGit(logArgs);
|
const result = runGit(logArgs)
|
||||||
|
|
||||||
const output = result.stdout.toString("utf-8");
|
const output = result.stdout.toString('utf-8')
|
||||||
const containsSkipCommit = output.indexOf(skipChangelogInfix) >= 0;
|
const containsSkipCommit = output.indexOf(skipChangelogInfix) >= 0
|
||||||
return containsSkipCommit;
|
return containsSkipCommit
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasChangelogModified()) {
|
if (wasChangelogModified()) {
|
||||||
console.log("Changelog was changed");
|
console.log('Changelog was changed')
|
||||||
process.exit(0);
|
process.exit(0)
|
||||||
} else {
|
} else {
|
||||||
console.log("No changes to the changelog");
|
console.log('No changes to the changelog')
|
||||||
if (isChangelogSkipped()) {
|
if (isChangelogSkipped()) {
|
||||||
console.log(
|
console.log(
|
||||||
"But one of the commits within the PR includes " +
|
'But one of the commits within the PR includes ' +
|
||||||
skipChangelogInfix +
|
skipChangelogInfix +
|
||||||
", so the check is skipped."
|
', so the check is skipped.'
|
||||||
);
|
)
|
||||||
process.exit(0);
|
process.exit(0)
|
||||||
} else {
|
} else {
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
|
|
||||||
const path = "build.sbt";
|
const path = 'build.sbt'
|
||||||
const version = process.argv[2];
|
const version = process.argv[2]
|
||||||
const edition = process.argv[3];
|
const edition = process.argv[3]
|
||||||
|
|
||||||
const content = fs.readFileSync(path, { encoding: "utf-8" });
|
const content = fs.readFileSync(path, { encoding: 'utf-8' })
|
||||||
const updated = content
|
const updated = content
|
||||||
.replace(/val ensoVersion.*= ".*"/, 'val ensoVersion = "' + version + '"')
|
.replace(/val ensoVersion.*= ".*"/, 'val ensoVersion = "' + version + '"')
|
||||||
.replace(
|
.replace(/val currentEdition.*= ".*"/, 'val currentEdition = "' + edition + '"')
|
||||||
/val currentEdition.*= ".*"/,
|
fs.writeFileSync(path, updated)
|
||||||
'val currentEdition = "' + edition + '"'
|
|
||||||
);
|
|
||||||
fs.writeFileSync(path, updated);
|
|
||||||
|
|
||||||
console.log("Updated build version to " + version);
|
console.log('Updated build version to ' + version)
|
||||||
console.log("Updated build edition to " + edition);
|
console.log('Updated build edition to ' + edition)
|
||||||
|
@ -1,59 +1,56 @@
|
|||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
|
|
||||||
const inputPath = process.argv[2];
|
const inputPath = process.argv[2]
|
||||||
const outputPath = process.argv[3];
|
const outputPath = process.argv[3]
|
||||||
|
|
||||||
console.log("Extracting release notes from " + inputPath + " to " + outputPath);
|
console.log('Extracting release notes from ' + inputPath + ' to ' + outputPath)
|
||||||
|
|
||||||
/** Returns the part of the text until the second top-level heading (exclusive)
|
/** Returns the part of the text until the second top-level heading (exclusive)
|
||||||
* in Markdown formatting.
|
* in Markdown formatting.
|
||||||
*/
|
*/
|
||||||
function cutFirstSection(content) {
|
function cutFirstSection(content) {
|
||||||
const nightlySectionRegex = /^# Enso Next$/gm;
|
const nightlySectionRegex = /^# Enso Next$/gm
|
||||||
function findNightlySectionStart(text) {
|
function findNightlySectionStart(text) {
|
||||||
return text.search(nightlySectionRegex);
|
return text.search(nightlySectionRegex)
|
||||||
}
|
}
|
||||||
const regularSectionRegex = /^# Enso .*? \(\d\d\d\d-\d\d-\d\d\)$/gm;
|
const regularSectionRegex = /^# Enso .*? \(\d\d\d\d-\d\d-\d\d\)$/gm
|
||||||
function findFirstRegularSectionStart(text) {
|
function findFirstRegularSectionStart(text) {
|
||||||
return text.search(regularSectionRegex);
|
return text.search(regularSectionRegex)
|
||||||
}
|
}
|
||||||
function findNewline(text) {
|
function findNewline(text) {
|
||||||
return text.indexOf("\n");
|
return text.indexOf('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstHeading = findNightlySectionStart(content);
|
const firstHeading = findNightlySectionStart(content)
|
||||||
if (firstHeading < 0) {
|
if (firstHeading < 0) {
|
||||||
throw "Could not find the nightly section, matching " + nightlySectionRegex;
|
throw 'Could not find the nightly section, matching ' + nightlySectionRegex
|
||||||
}
|
}
|
||||||
|
|
||||||
const restOffset = firstHeading + 2;
|
const restOffset = firstHeading + 2
|
||||||
const newLineOffset = findNewline(content.substring(restOffset));
|
const newLineOffset = findNewline(content.substring(restOffset))
|
||||||
if (newLineOffset < 0) {
|
if (newLineOffset < 0) {
|
||||||
throw "No content after the section heading";
|
throw 'No content after the section heading'
|
||||||
}
|
}
|
||||||
const restStart = restOffset + newLineOffset + 1;
|
const restStart = restOffset + newLineOffset + 1
|
||||||
|
|
||||||
const rest = content.substring(restStart);
|
const rest = content.substring(restStart)
|
||||||
const secondHeading = findFirstRegularSectionStart(rest);
|
const secondHeading = findFirstRegularSectionStart(rest)
|
||||||
if (secondHeading < 0) {
|
if (secondHeading < 0) {
|
||||||
throw (
|
throw 'Could not find the first released section, matching' + regularSectionRegex
|
||||||
"Could not find the first released section, matching" +
|
}
|
||||||
regularSectionRegex
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstSectionContent = rest.substring(0, secondHeading);
|
const firstSectionContent = rest.substring(0, secondHeading)
|
||||||
return firstSectionContent;
|
return firstSectionContent
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(inputPath, { encoding: "utf-8" });
|
const content = fs.readFileSync(inputPath, { encoding: 'utf-8' })
|
||||||
const nightlyPart = cutFirstSection(content);
|
const nightlyPart = cutFirstSection(content)
|
||||||
fs.writeFileSync(outputPath, nightlyPart);
|
fs.writeFileSync(outputPath, nightlyPart)
|
||||||
|
|
||||||
console.log("Created " + outputPath + " with the following content:");
|
console.log('Created ' + outputPath + ' with the following content:')
|
||||||
console.log(nightlyPart);
|
console.log(nightlyPart)
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
console.error(exc);
|
console.error(exc)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,66 @@
|
|||||||
const { Octokit } = require("@octokit/core");
|
const { Octokit } = require('@octokit/core')
|
||||||
|
|
||||||
const organization = "enso-org";
|
const organization = 'enso-org'
|
||||||
function determineRepositoryName() {
|
function determineRepositoryName() {
|
||||||
const fallback = "enso";
|
const fallback = 'enso'
|
||||||
const fallbackMessage =
|
const fallbackMessage = 'Could not determine the repository name, falling back to the default.'
|
||||||
"Could not determine the repository name, falling back to the default.";
|
const fullName = process.env.GITHUB_REPOSITORY
|
||||||
const fullName = process.env.GITHUB_REPOSITORY;
|
if (!fullName) {
|
||||||
if (!fullName) {
|
console.log(fallbackMessage)
|
||||||
console.log(fallbackMessage);
|
return fallback
|
||||||
return fallback;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const prefix = organization + "/";
|
const prefix = organization + '/'
|
||||||
if (fullName.startsWith(prefix)) {
|
if (fullName.startsWith(prefix)) {
|
||||||
return fullName.substring(prefix.length);
|
return fullName.substring(prefix.length)
|
||||||
} else {
|
} else {
|
||||||
console.log(fallbackMessage);
|
console.log(fallbackMessage)
|
||||||
return fallback;
|
return fallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const repo = determineRepositoryName();
|
const repo = determineRepositoryName()
|
||||||
const token = process.env.GITHUB_TOKEN;
|
const token = process.env.GITHUB_TOKEN
|
||||||
const octokit = new Octokit({ auth: token });
|
const octokit = new Octokit({ auth: token })
|
||||||
|
|
||||||
function isNightly(release) {
|
function isNightly(release) {
|
||||||
const nightlyInfix = "Nightly";
|
const nightlyInfix = 'Nightly'
|
||||||
return release.name.indexOf(nightlyInfix) >= 0 && !release.draft;
|
return release.name.indexOf(nightlyInfix) >= 0 && !release.draft
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAllReleases() {
|
async function fetchAllReleases() {
|
||||||
const res = await octokit.request("GET /repos/{owner}/{repo}/releases", {
|
const res = await octokit.request('GET /repos/{owner}/{repo}/releases', {
|
||||||
owner: organization,
|
owner: organization,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
});
|
})
|
||||||
return res.data;
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchNightlies() {
|
async function fetchNightlies() {
|
||||||
const releases = await fetchAllReleases();
|
const releases = await fetchAllReleases()
|
||||||
const nightlies = releases.filter(isNightly);
|
const nightlies = releases.filter(isNightly)
|
||||||
return nightlies;
|
return nightlies
|
||||||
}
|
}
|
||||||
|
|
||||||
async function triggerWorkflow(repo, workflow_id, ref) {
|
async function triggerWorkflow(repo, workflow_id, ref) {
|
||||||
await octokit.request(
|
await octokit.request('POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches', {
|
||||||
"POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches",
|
owner: organization,
|
||||||
{
|
repo: repo,
|
||||||
owner: organization,
|
workflow_id: workflow_id,
|
||||||
repo: repo,
|
ref: ref,
|
||||||
workflow_id: workflow_id,
|
})
|
||||||
ref: ref,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function publishRelease(id) {
|
async function publishRelease(id) {
|
||||||
return await octokit.request(
|
return await octokit.request('PATCH /repos/{owner}/{repo}/releases/{release_id}', {
|
||||||
"PATCH /repos/{owner}/{repo}/releases/{release_id}",
|
owner: organization,
|
||||||
{
|
repo: repo,
|
||||||
owner: organization,
|
release_id: id,
|
||||||
repo: repo,
|
draft: false,
|
||||||
release_id: id,
|
})
|
||||||
draft: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchAllReleases = fetchAllReleases;
|
exports.fetchAllReleases = fetchAllReleases
|
||||||
exports.fetchNightlies = fetchNightlies;
|
exports.fetchNightlies = fetchNightlies
|
||||||
exports.publishRelease = publishRelease;
|
exports.publishRelease = publishRelease
|
||||||
exports.repository = repo;
|
exports.repository = repo
|
||||||
|
@ -1,69 +1,67 @@
|
|||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
const github = require("./github");
|
const github = require('./github')
|
||||||
|
|
||||||
const currentHeadSha = process.argv[2];
|
const currentHeadSha = process.argv[2]
|
||||||
const buildConfigPath = "../../../build.sbt";
|
const buildConfigPath = '../../../build.sbt'
|
||||||
|
|
||||||
/// Returns the current date formatted as 'YYYY-mm-dd'.
|
/// Returns the current date formatted as 'YYYY-mm-dd'.
|
||||||
function isoDate() {
|
function isoDate() {
|
||||||
const now = new Date();
|
const now = new Date()
|
||||||
const year = "" + now.getFullYear();
|
const year = '' + now.getFullYear()
|
||||||
let month = "" + (now.getMonth() + 1);
|
let month = '' + (now.getMonth() + 1)
|
||||||
let day = "" + now.getDate();
|
let day = '' + now.getDate()
|
||||||
if (month.length < 2) {
|
if (month.length < 2) {
|
||||||
month = "0" + month;
|
month = '0' + month
|
||||||
}
|
}
|
||||||
if (day.length < 2) {
|
if (day.length < 2) {
|
||||||
day = "0" + day;
|
day = '0' + day
|
||||||
}
|
}
|
||||||
return year + "-" + month + "-" + day;
|
return year + '-' + month + '-' + day
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the step output 'proceed'.
|
/// Sets the step output 'proceed'.
|
||||||
function setProceed(proceed) {
|
function setProceed(proceed) {
|
||||||
console.log("::set-output name=proceed::" + proceed);
|
console.log('::set-output name=proceed::' + proceed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the step output 'nightly-version'.
|
/// Sets the step output 'nightly-version'.
|
||||||
function setVersionString(name) {
|
function setVersionString(name) {
|
||||||
console.log("::set-output name=nightly-version::" + name);
|
console.log('::set-output name=nightly-version::' + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the step output 'nightly-edition'.
|
/// Sets the step output 'nightly-edition'.
|
||||||
function setEditionName(name) {
|
function setEditionName(name) {
|
||||||
console.log("::set-output name=nightly-edition::" + name);
|
console.log('::set-output name=nightly-edition::' + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks if there are any new changes to see if the nightly build should
|
/** Checks if there are any new changes to see if the nightly build should
|
||||||
* proceed.
|
* proceed.
|
||||||
*/
|
*/
|
||||||
function checkProceed(nightlies) {
|
function checkProceed(nightlies) {
|
||||||
if (nightlies.length == 0) {
|
if (nightlies.length == 0) {
|
||||||
console.log(
|
console.log('No prior nightly releases found. Proceeding with the first release.')
|
||||||
"No prior nightly releases found. Proceeding with the first release."
|
return true
|
||||||
);
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const first = nightlies[0];
|
const first = nightlies[0]
|
||||||
const firstNightlySha = first.target_commitish;
|
const firstNightlySha = first.target_commitish
|
||||||
if (firstNightlySha == currentHeadSha) {
|
if (firstNightlySha == currentHeadSha) {
|
||||||
console.log(
|
console.log(
|
||||||
"Current commit (" +
|
'Current commit (' +
|
||||||
currentHeadSha +
|
currentHeadSha +
|
||||||
") is the same as for the most recent nightly build. A new build is not needed."
|
') is the same as for the most recent nightly build. A new build is not needed.'
|
||||||
);
|
)
|
||||||
return false;
|
return false
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
"Current commit (" +
|
'Current commit (' +
|
||||||
currentHeadSha +
|
currentHeadSha +
|
||||||
") is different from the most recent nightly build (" +
|
') is different from the most recent nightly build (' +
|
||||||
firstNightlySha +
|
firstNightlySha +
|
||||||
"). Proceeding with a new nightly build."
|
'). Proceeding with a new nightly build.'
|
||||||
);
|
)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prepares a version string and edition name for the nightly build.
|
/** Prepares a version string and edition name for the nightly build.
|
||||||
@ -73,60 +71,60 @@ function checkProceed(nightlies) {
|
|||||||
* increasing numeric suffix is added.
|
* increasing numeric suffix is added.
|
||||||
*/
|
*/
|
||||||
function prepareVersions(nightlies) {
|
function prepareVersions(nightlies) {
|
||||||
function isTaken(suffix) {
|
function isTaken(suffix) {
|
||||||
return nightlies.some((entry) => entry.tag_name.endsWith(suffix));
|
return nightlies.some(entry => entry.tag_name.endsWith(suffix))
|
||||||
}
|
|
||||||
|
|
||||||
const content = fs.readFileSync(buildConfigPath, { encoding: "utf-8" });
|
|
||||||
const match = content.match(/val ensoVersion += +"(.*)"/);
|
|
||||||
if (!match) {
|
|
||||||
console.error("Could not find the version string in configuration!");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const version = match[1];
|
|
||||||
let baseName = version;
|
|
||||||
if (!baseName.endsWith("SNAPSHOT")) {
|
|
||||||
baseName += "-SNAPSHOT";
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = isoDate();
|
|
||||||
function makeSuffix(ix) {
|
|
||||||
if (ix == 0) {
|
|
||||||
return now;
|
|
||||||
} else {
|
|
||||||
return now + "." + ix;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let ix = 0;
|
const content = fs.readFileSync(buildConfigPath, { encoding: 'utf-8' })
|
||||||
while (isTaken(makeSuffix(ix))) {
|
const match = content.match(/val ensoVersion += +"(.*)"/)
|
||||||
ix++;
|
if (!match) {
|
||||||
}
|
console.error('Could not find the version string in configuration!')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
const suffix = makeSuffix(ix);
|
const version = match[1]
|
||||||
const versionName = baseName + "." + suffix;
|
let baseName = version
|
||||||
const edition = "nightly-" + suffix;
|
if (!baseName.endsWith('SNAPSHOT')) {
|
||||||
console.log("The build will be using version '" + versionName + "'");
|
baseName += '-SNAPSHOT'
|
||||||
console.log("The build will be using edition '" + edition + "'");
|
}
|
||||||
return {
|
|
||||||
version: versionName,
|
const now = isoDate()
|
||||||
edition: edition,
|
function makeSuffix(ix) {
|
||||||
};
|
if (ix == 0) {
|
||||||
|
return now
|
||||||
|
} else {
|
||||||
|
return now + '.' + ix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ix = 0
|
||||||
|
while (isTaken(makeSuffix(ix))) {
|
||||||
|
ix++
|
||||||
|
}
|
||||||
|
|
||||||
|
const suffix = makeSuffix(ix)
|
||||||
|
const versionName = baseName + '.' + suffix
|
||||||
|
const edition = 'nightly-' + suffix
|
||||||
|
console.log("The build will be using version '" + versionName + "'")
|
||||||
|
console.log("The build will be using edition '" + edition + "'")
|
||||||
|
return {
|
||||||
|
version: versionName,
|
||||||
|
edition: edition,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const nightlies = await github.fetchNightlies();
|
const nightlies = await github.fetchNightlies()
|
||||||
const shouldProceed = checkProceed(nightlies);
|
const shouldProceed = checkProceed(nightlies)
|
||||||
setProceed(shouldProceed);
|
setProceed(shouldProceed)
|
||||||
if (shouldProceed) {
|
if (shouldProceed) {
|
||||||
const versions = prepareVersions(nightlies);
|
const versions = prepareVersions(nightlies)
|
||||||
setVersionString(versions.version);
|
setVersionString(versions.version)
|
||||||
setEditionName(versions.edition);
|
setEditionName(versions.edition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err) => {
|
main().catch(err => {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
});
|
})
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
const github = require("./github");
|
const github = require('./github')
|
||||||
|
|
||||||
const releaseId = process.argv[2];
|
const releaseId = process.argv[2]
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log("Making release " + releaseId + " public.");
|
console.log('Making release ' + releaseId + ' public.')
|
||||||
await github.publishRelease(releaseId);
|
await github.publishRelease(releaseId)
|
||||||
console.log("Done.");
|
console.log('Done.')
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err) => {
|
main().catch(err => {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
});
|
})
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
const github = require("./github");
|
const github = require('./github')
|
||||||
|
|
||||||
const repo = process.argv[2];
|
const repo = process.argv[2]
|
||||||
const workflow_id = process.argv[3];
|
const workflow_id = process.argv[3]
|
||||||
const ref = process.argv[4];
|
const ref = process.argv[4]
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log(
|
console.log('Triggering workflow ' + workflow_id + ' in ' + repo + ' on ' + ref)
|
||||||
"Triggering workflow " + workflow_id + " in " + repo + " on " + ref
|
await github.triggerWorkflow(repo, workflow_id, ref)
|
||||||
);
|
console.log('Done.')
|
||||||
await github.triggerWorkflow(repo, workflow_id, ref);
|
|
||||||
console.log("Done.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err) => {
|
main().catch(err => {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
});
|
})
|
||||||
|
@ -1,54 +1,54 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
let usage = `Usage: add-release.js PATH TAG [ASSETS...]
|
let usage = `Usage: add-release.js PATH TAG [ASSETS...]
|
||||||
|
|
||||||
Updates the release list at PATH by adding a new release (if it does not exist)
|
Updates the release list at PATH by adding a new release (if it does not exist)
|
||||||
with the provided TAG and list of ASSETS.`;
|
with the provided TAG and list of ASSETS.`
|
||||||
|
|
||||||
if (process.argv.length < 4) {
|
if (process.argv.length < 4) {
|
||||||
console.log(usage);
|
console.log(usage)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = process.argv[2];
|
let path = process.argv[2]
|
||||||
let tag = process.argv[3];
|
let tag = process.argv[3]
|
||||||
let assets = process.argv.slice(4);
|
let assets = process.argv.slice(4)
|
||||||
|
|
||||||
if (assets.length == 0) {
|
if (assets.length == 0) {
|
||||||
console.error("Adding a release with no assets.");
|
console.error('Adding a release with no assets.')
|
||||||
}
|
}
|
||||||
|
|
||||||
function releaseAlreadyExists(root, tag) {
|
function releaseAlreadyExists(root, tag) {
|
||||||
let existing = root["releases"].find((release) => release["tag"] == tag);
|
let existing = root['releases'].find(release => release['tag'] == tag)
|
||||||
return existing !== undefined;
|
return existing !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readFile(path, "utf8", (err, data) => {
|
fs.readFile(path, 'utf8', (err, data) => {
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = JSON.parse(data);
|
|
||||||
if (releaseAlreadyExists(root, tag)) {
|
|
||||||
console.error(`Release '${tag}' already exists.`);
|
|
||||||
console.error("No changes written.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let release = {
|
|
||||||
tag: tag,
|
|
||||||
assets: assets,
|
|
||||||
};
|
|
||||||
|
|
||||||
root["releases"].push(release);
|
|
||||||
|
|
||||||
fs.writeFile(path, JSON.stringify(root, null, 1) + "\n", (err) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
} else {
|
|
||||||
console.error(`Added release ${tag} with assets ${assets}.`);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
let root = JSON.parse(data)
|
||||||
|
if (releaseAlreadyExists(root, tag)) {
|
||||||
|
console.error(`Release '${tag}' already exists.`)
|
||||||
|
console.error('No changes written.')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let release = {
|
||||||
|
tag: tag,
|
||||||
|
assets: assets,
|
||||||
|
}
|
||||||
|
|
||||||
|
root['releases'].push(release)
|
||||||
|
|
||||||
|
fs.writeFile(path, JSON.stringify(root, null, 1) + '\n', err => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(2)
|
||||||
|
} else {
|
||||||
|
console.error(`Added release ${tag} with assets ${assets}.`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
let usage = `Usage: is-broken.js PATH
|
let usage = `Usage: is-broken.js PATH
|
||||||
|
|
||||||
Reads the release metadata at PATH (in JSON format) and checks if it contains
|
Reads the release metadata at PATH (in JSON format) and checks if it contains
|
||||||
the broken mark. Exit code 0 indicates that the release contains the broken
|
the broken mark. Exit code 0 indicates that the release contains the broken
|
||||||
mark. Other exit codes mean that the release either could not be loaded or is
|
mark. Other exit codes mean that the release either could not be loaded or is
|
||||||
not marked broken. If the release is marked as broken, it also prints the URL to
|
not marked broken. If the release is marked as broken, it also prints the URL to
|
||||||
download the broken mark file.`;
|
download the broken mark file.`
|
||||||
|
|
||||||
if (process.argv.length != 3) {
|
if (process.argv.length != 3) {
|
||||||
console.log(usage);
|
console.log(usage)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = process.argv[2];
|
let path = process.argv[2]
|
||||||
|
|
||||||
function findBrokenMark(release) {
|
function findBrokenMark(release) {
|
||||||
let assets = release["assets"];
|
let assets = release['assets']
|
||||||
return assets.find((asset) => asset["name"] == "broken");
|
return assets.find(asset => asset['name'] == 'broken')
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readFile(path, "utf8", (err, data) => {
|
fs.readFile(path, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
let release = JSON.parse(data);
|
let release = JSON.parse(data)
|
||||||
let mark = findBrokenMark(release);
|
let mark = findBrokenMark(release)
|
||||||
if (mark) {
|
if (mark) {
|
||||||
console.error("Release is marked as broken.");
|
console.error('Release is marked as broken.')
|
||||||
console.log(mark["url"]);
|
console.log(mark['url'])
|
||||||
process.exit(0);
|
process.exit(0)
|
||||||
} else {
|
} else {
|
||||||
console.error("Release is NOT marked as broken.");
|
console.error('Release is NOT marked as broken.')
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
@ -1,43 +1,43 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
let usage = `Usage: mark-broken.js PATH TAG
|
let usage = `Usage: mark-broken.js PATH TAG
|
||||||
|
|
||||||
Updates the release list at PATH by adding the broken mark to the release with
|
Updates the release list at PATH by adding the broken mark to the release with
|
||||||
tag TAG.`;
|
tag TAG.`
|
||||||
|
|
||||||
if (process.argv.length != 4) {
|
if (process.argv.length != 4) {
|
||||||
console.log(usage);
|
console.log(usage)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = process.argv[2];
|
let path = process.argv[2]
|
||||||
let tag = process.argv[3];
|
let tag = process.argv[3]
|
||||||
|
|
||||||
fs.readFile(path, "utf8", (err, data) => {
|
fs.readFile(path, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
let root = JSON.parse(data);
|
let root = JSON.parse(data)
|
||||||
let release = root["releases"].find((release) => release["tag"] == tag);
|
let release = root['releases'].find(release => release['tag'] == tag)
|
||||||
if (release === undefined) {
|
if (release === undefined) {
|
||||||
console.error(`Release '${tag}' is not present in the metadata.`);
|
console.error(`Release '${tag}' is not present in the metadata.`)
|
||||||
console.error("No changes written.");
|
console.error('No changes written.')
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (release["assets"].includes("broken")) {
|
if (release['assets'].includes('broken')) {
|
||||||
console.error("Broken mark is already present in the metadata.");
|
console.error('Broken mark is already present in the metadata.')
|
||||||
} else {
|
} else {
|
||||||
release["assets"].push("broken");
|
release['assets'].push('broken')
|
||||||
fs.writeFile(path, JSON.stringify(root, null, 1) + "\n", (err) => {
|
fs.writeFile(path, JSON.stringify(root, null, 1) + '\n', err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
process.exit(2);
|
process.exit(2)
|
||||||
} else {
|
} else {
|
||||||
console.error("Broken mark has been added.");
|
console.error('Broken mark has been added.')
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
@ -1,140 +1,136 @@
|
|||||||
const reviewRoot = "../../target";
|
const reviewRoot = '../../target'
|
||||||
const settingsRoot = "../../tools/legal-review";
|
const settingsRoot = '../../tools/legal-review'
|
||||||
|
|
||||||
const express = require("express");
|
const express = require('express')
|
||||||
const app = express();
|
const app = express()
|
||||||
const open = require("open");
|
const open = require('open')
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
const path = require("path");
|
const path = require('path')
|
||||||
|
|
||||||
// The home page that lists available reports.
|
// The home page that lists available reports.
|
||||||
app.get("/", function (req, res) {
|
app.get('/', function (req, res) {
|
||||||
let html = "<h1>Report review</h1>";
|
let html = '<h1>Report review</h1>'
|
||||||
const files = fs.readdirSync(reviewRoot);
|
const files = fs.readdirSync(reviewRoot)
|
||||||
const reports = files
|
const reports = files
|
||||||
.map((f) => f.match(/^(.*)-report.html$/))
|
.map(f => f.match(/^(.*)-report.html$/))
|
||||||
.filter((m) => m != null)
|
.filter(m => m != null)
|
||||||
.map((m) => m[1]);
|
.map(m => m[1])
|
||||||
if (reports.length == 0) {
|
if (reports.length == 0) {
|
||||||
html +=
|
html +=
|
||||||
"No reports found. " +
|
'No reports found. ' +
|
||||||
'Run <pre style="display:inline">enso / gatherLicenses</pre> first.';
|
'Run <pre style="display:inline">enso / gatherLicenses</pre> first.'
|
||||||
} else {
|
} else {
|
||||||
html += "Select report:";
|
html += 'Select report:'
|
||||||
html += "<ul>";
|
html += '<ul>'
|
||||||
reports.forEach((report) => {
|
reports.forEach(report => {
|
||||||
html += '<li><a href="/report/' + report + '">' + report + "</a></li>";
|
html += '<li><a href="/report/' + report + '">' + report + '</a></li>'
|
||||||
});
|
})
|
||||||
html += "</ul>";
|
html += '</ul>'
|
||||||
}
|
}
|
||||||
res.send(html);
|
res.send(html)
|
||||||
});
|
})
|
||||||
|
|
||||||
// Serves the injection script.
|
// Serves the injection script.
|
||||||
app.use("/static", express.static("static"));
|
app.use('/static', express.static('static'))
|
||||||
|
|
||||||
// Serves contents of the given report, injecting the review-mode script.
|
// Serves contents of the given report, injecting the review-mode script.
|
||||||
app.get("/report/:report", function (req, res) {
|
app.get('/report/:report', function (req, res) {
|
||||||
const report = req.params["report"];
|
const report = req.params['report']
|
||||||
console.log("Opening report for ", report);
|
console.log('Opening report for ', report)
|
||||||
fs.readFile(
|
fs.readFile(path.join(reviewRoot, report + '-report.html'), 'utf-8', (err, data) => {
|
||||||
path.join(reviewRoot, report + "-report.html"),
|
const injection =
|
||||||
"utf-8",
|
'<script src="/static/inject.js"></script>' +
|
||||||
(err, data) => {
|
'<script>var reportName = "' +
|
||||||
const injection =
|
report +
|
||||||
'<script src="/static/inject.js"></script>' +
|
'";</script>'
|
||||||
'<script>var reportName = "' +
|
if (err) {
|
||||||
report +
|
res.status(400).send(err)
|
||||||
'";</script>';
|
} else {
|
||||||
if (err) {
|
const injected = data.replace('</head>', injection + '</head>')
|
||||||
res.status(400).send(err);
|
res.send(injected)
|
||||||
} else {
|
}
|
||||||
const injected = data.replace("</head>", injection + "</head>");
|
})
|
||||||
res.send(injected);
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Appends a line to the setting file.
|
// Appends a line to the setting file.
|
||||||
function addLine(report, package, file, line) {
|
function addLine(report, package, file, line) {
|
||||||
const dir = path.join(settingsRoot, report, package);
|
const dir = path.join(settingsRoot, report, package)
|
||||||
const location = path.join(dir, file);
|
const location = path.join(dir, file)
|
||||||
console.log("Adding " + line + " to " + location);
|
console.log('Adding ' + line + ' to ' + location)
|
||||||
fs.mkdirSync(dir, {
|
fs.mkdirSync(dir, {
|
||||||
recursive: true,
|
recursive: true,
|
||||||
});
|
})
|
||||||
fs.appendFileSync(location, line + "\n");
|
fs.appendFileSync(location, line + '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a line from the setting file.
|
// Removes a line from the setting file.
|
||||||
function removeLine(report, package, file, line) {
|
function removeLine(report, package, file, line) {
|
||||||
const location = path.join(settingsRoot, report, package, file);
|
const location = path.join(settingsRoot, report, package, file)
|
||||||
console.log("Removing " + line + " from " + location);
|
console.log('Removing ' + line + ' from ' + location)
|
||||||
const lines = fs
|
const lines = fs
|
||||||
.readFileSync(location, "utf-8")
|
.readFileSync(location, 'utf-8')
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
.filter((x) => x.length > 0);
|
.filter(x => x.length > 0)
|
||||||
const toRemove = lines.filter((x) => x == line);
|
const toRemove = lines.filter(x => x == line)
|
||||||
const others = lines.filter((x) => x != line);
|
const others = lines.filter(x => x != line)
|
||||||
if (toRemove.length == 0) {
|
if (toRemove.length == 0) {
|
||||||
throw (
|
throw (
|
||||||
"Line " +
|
'Line ' +
|
||||||
line +
|
line +
|
||||||
" was not present in the file. " +
|
' was not present in the file. ' +
|
||||||
"Are you sure the report is up to date?"
|
'Are you sure the report is up to date?'
|
||||||
);
|
)
|
||||||
} else {
|
} else {
|
||||||
var newContent = others.join("\n") + "\n";
|
var newContent = others.join('\n') + '\n'
|
||||||
if (others.length == 0) {
|
if (others.length == 0) {
|
||||||
newContent = "";
|
newContent = ''
|
||||||
|
}
|
||||||
|
fs.writeFileSync(location, newContent)
|
||||||
}
|
}
|
||||||
fs.writeFileSync(location, newContent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles the requests to add or remove lines.
|
// Handles the requests to add or remove lines.
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }))
|
||||||
app.post("/modify/:report", function (req, res) {
|
app.post('/modify/:report', function (req, res) {
|
||||||
const report = req.params["report"];
|
const report = req.params['report']
|
||||||
const package = req.body["package"];
|
const package = req.body['package']
|
||||||
const action = req.body["action"];
|
const action = req.body['action']
|
||||||
const file = req.body["file"];
|
const file = req.body['file']
|
||||||
let line = req.body["line"];
|
let line = req.body['line']
|
||||||
const encodedLine = req.body["encoded_line"];
|
const encodedLine = req.body['encoded_line']
|
||||||
if (encodedLine !== undefined) {
|
if (encodedLine !== undefined) {
|
||||||
line = Buffer.from(encodedLine, "base64").toString();
|
line = Buffer.from(encodedLine, 'base64').toString()
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (action == "add") {
|
|
||||||
addLine(report, package, file, line);
|
|
||||||
} else if (action == "remove") {
|
|
||||||
removeLine(report, package, file, line);
|
|
||||||
} else {
|
|
||||||
throw "Unknown action";
|
|
||||||
}
|
}
|
||||||
res.send("OK");
|
|
||||||
} catch (error) {
|
try {
|
||||||
console.error(error);
|
if (action == 'add') {
|
||||||
res.status(500).send(error);
|
addLine(report, package, file, line)
|
||||||
}
|
} else if (action == 'remove') {
|
||||||
});
|
removeLine(report, package, file, line)
|
||||||
|
} else {
|
||||||
|
throw 'Unknown action'
|
||||||
|
}
|
||||||
|
res.send('OK')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
res.status(500).send(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Listens on a random free port, opens a browser with the home page and waits
|
* Listens on a random free port, opens a browser with the home page and waits
|
||||||
* for a newline to terminate.
|
* for a newline to terminate.
|
||||||
*/
|
*/
|
||||||
const server = app.listen(0, () => {
|
const server = app.listen(0, () => {
|
||||||
const port = server.address().port;
|
const port = server.address().port
|
||||||
console.log("Listening on at ", "http://localhost:" + port + "/");
|
console.log('Listening on at ', 'http://localhost:' + port + '/')
|
||||||
open("http://localhost:" + port + "/");
|
open('http://localhost:' + port + '/')
|
||||||
|
|
||||||
console.log("Press ENTER to stop the server.");
|
console.log('Press ENTER to stop the server.')
|
||||||
process.stdin.on("data", function (chunk) {
|
process.stdin.on('data', function (chunk) {
|
||||||
if (chunk.indexOf("\n") >= 0) {
|
if (chunk.indexOf('\n') >= 0) {
|
||||||
console.log("Good bye");
|
console.log('Good bye')
|
||||||
process.exit(0);
|
process.exit(0)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
@ -1,140 +1,128 @@
|
|||||||
/** Sets a status text in bottom left part of the screen. */
|
/** Sets a status text in bottom left part of the screen. */
|
||||||
function setStatus(text, color) {
|
function setStatus(text, color) {
|
||||||
var status = $("#status");
|
var status = $('#status')
|
||||||
status.html(text);
|
status.html(text)
|
||||||
if (color === undefined) {
|
if (color === undefined) {
|
||||||
color = "white";
|
color = 'white'
|
||||||
}
|
}
|
||||||
status.css("background-color", color);
|
status.css('background-color', color)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a handler that will request to add or remove a line from a file. */
|
/** Creates a handler that will request to add or remove a line from a file. */
|
||||||
function makeHandler(elem, data, file, action) {
|
function makeHandler(elem, data, file, action) {
|
||||||
return function (ev) {
|
return function (ev) {
|
||||||
data["file"] = file;
|
data['file'] = file
|
||||||
data["action"] = action;
|
data['action'] = action
|
||||||
$.post("/modify/" + reportName, data, function (response) {
|
$.post('/modify/' + reportName, data, function (response) {
|
||||||
$(elem).html(
|
$(elem).html(
|
||||||
'<span style="color:gray">Modified, if you want to ' +
|
'<span style="color:gray">Modified, if you want to ' +
|
||||||
"change this value, regenerate the report first</span>"
|
'change this value, regenerate the report first</span>'
|
||||||
);
|
)
|
||||||
var tab = $(elem).closest("div").parent();
|
var tab = $(elem).closest('div').parent()
|
||||||
var title = tab.children("h4");
|
var title = tab.children('h4')
|
||||||
tab.accordion("option", "active", false);
|
tab.accordion('option', 'active', false)
|
||||||
var info = "added " + file;
|
var info = 'added ' + file
|
||||||
if (action == "remove") {
|
if (action == 'remove') {
|
||||||
info = "undone review";
|
info = 'undone review'
|
||||||
}
|
}
|
||||||
var newTitle =
|
var newTitle =
|
||||||
'<span style="text-decoration: line-through;">' +
|
'<span style="text-decoration: line-through;">' +
|
||||||
title.html() +
|
title.html() +
|
||||||
"</span><br>" +
|
'</span><br>' +
|
||||||
info;
|
info
|
||||||
title.html(newTitle);
|
title.html(newTitle)
|
||||||
title.find("span").css("color", "gray");
|
title.find('span').css('color', 'gray')
|
||||||
setStatus("Review for " + data["package"] + " sent.");
|
setStatus('Review for ' + data['package'] + ' sent.')
|
||||||
}).fail(function (err) {
|
}).fail(function (err) {
|
||||||
setStatus("Failed to send review: " + JSON.stringify(err), "red");
|
setStatus('Failed to send review: ' + JSON.stringify(err), 'red')
|
||||||
});
|
})
|
||||||
setStatus("Sending review...");
|
setStatus('Sending review...')
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
$("body").prepend(
|
$('body').prepend(
|
||||||
'<div style="color:red">This review helper tool does not regenerate the ' +
|
'<div style="color:red">This review helper tool does not regenerate the ' +
|
||||||
"report - to see the changes that are applied using this tool after " +
|
'report - to see the changes that are applied using this tool after ' +
|
||||||
"refreshing the page, you need to regenerate the report using the " +
|
'refreshing the page, you need to regenerate the report using the ' +
|
||||||
"`gatherLicenses` command.</div>"
|
'`gatherLicenses` command.</div>'
|
||||||
);
|
)
|
||||||
$("body").append(
|
$('body').append(
|
||||||
'<div id="status" ' +
|
'<div id="status" ' + 'style="position: fixed;left:4pt;bottom:4pt">' + 'Loading...</div>'
|
||||||
'style="position: fixed;left:4pt;bottom:4pt">' +
|
)
|
||||||
"Loading...</div>"
|
var copys = $('.copyright-ui')
|
||||||
);
|
var files = $('.file-ui')
|
||||||
var copys = $(".copyright-ui");
|
|
||||||
var files = $(".file-ui");
|
|
||||||
|
|
||||||
copyrightMap = {
|
copyrightMap = {
|
||||||
Ignore: "copyright-ignore",
|
Ignore: 'copyright-ignore',
|
||||||
KeepWithContext: "copyright-keep-context",
|
KeepWithContext: 'copyright-keep-context',
|
||||||
Keep: "copyright-keep",
|
Keep: 'copyright-keep',
|
||||||
};
|
|
||||||
|
|
||||||
copys.each(function (index) {
|
|
||||||
var package = $(this).data("package");
|
|
||||||
var encodedContent = $(this).data("content");
|
|
||||||
var status = $(this).data("status");
|
|
||||||
var contexts = parseInt($(this).data("contexts"));
|
|
||||||
var data = {
|
|
||||||
encoded_line: encodedContent,
|
|
||||||
package: package,
|
|
||||||
};
|
|
||||||
if (status == "NotReviewed") {
|
|
||||||
var buttons =
|
|
||||||
'<button class="ignore">Ignore</button>' +
|
|
||||||
'<button class="keep">Keep</button>' +
|
|
||||||
'<button class="keepctx">Keep as context</button>';
|
|
||||||
$(this).html(buttons);
|
|
||||||
$(this)
|
|
||||||
.children(".ignore")
|
|
||||||
.on("click", makeHandler(this, data, "copyright-ignore", "add"));
|
|
||||||
$(this)
|
|
||||||
.children(".keep")
|
|
||||||
.on("click", makeHandler(this, data, "copyright-keep", "add"));
|
|
||||||
if (contexts == 1) {
|
|
||||||
$(this)
|
|
||||||
.children(".keepctx")
|
|
||||||
.on(
|
|
||||||
"click",
|
|
||||||
makeHandler(this, data, "copyright-keep-context", "add")
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$(this).children(".keepctx").attr("disabled", true);
|
|
||||||
}
|
|
||||||
} else if (status != "Added") {
|
|
||||||
$(this).html("<button>Undo review</button>");
|
|
||||||
$(this)
|
|
||||||
.children("button")
|
|
||||||
.on("click", makeHandler(this, data, copyrightMap[status], "remove"));
|
|
||||||
} else {
|
|
||||||
$(this).html("<button disabled>This notice was added manually</button>");
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
filesMap = {
|
copys.each(function (index) {
|
||||||
Ignore: "files-ignore",
|
var package = $(this).data('package')
|
||||||
Keep: "files-keep",
|
var encodedContent = $(this).data('content')
|
||||||
};
|
var status = $(this).data('status')
|
||||||
|
var contexts = parseInt($(this).data('contexts'))
|
||||||
|
var data = {
|
||||||
|
encoded_line: encodedContent,
|
||||||
|
package: package,
|
||||||
|
}
|
||||||
|
if (status == 'NotReviewed') {
|
||||||
|
var buttons =
|
||||||
|
'<button class="ignore">Ignore</button>' +
|
||||||
|
'<button class="keep">Keep</button>' +
|
||||||
|
'<button class="keepctx">Keep as context</button>'
|
||||||
|
$(this).html(buttons)
|
||||||
|
$(this)
|
||||||
|
.children('.ignore')
|
||||||
|
.on('click', makeHandler(this, data, 'copyright-ignore', 'add'))
|
||||||
|
$(this).children('.keep').on('click', makeHandler(this, data, 'copyright-keep', 'add'))
|
||||||
|
if (contexts == 1) {
|
||||||
|
$(this)
|
||||||
|
.children('.keepctx')
|
||||||
|
.on('click', makeHandler(this, data, 'copyright-keep-context', 'add'))
|
||||||
|
} else {
|
||||||
|
$(this).children('.keepctx').attr('disabled', true)
|
||||||
|
}
|
||||||
|
} else if (status != 'Added') {
|
||||||
|
$(this).html('<button>Undo review</button>')
|
||||||
|
$(this)
|
||||||
|
.children('button')
|
||||||
|
.on('click', makeHandler(this, data, copyrightMap[status], 'remove'))
|
||||||
|
} else {
|
||||||
|
$(this).html('<button disabled>This notice was added manually</button>')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
files.each(function (index) {
|
filesMap = {
|
||||||
var package = $(this).data("package");
|
Ignore: 'files-ignore',
|
||||||
var filename = $(this).data("filename");
|
Keep: 'files-keep',
|
||||||
var status = $(this).data("status");
|
|
||||||
var data = {
|
|
||||||
line: filename,
|
|
||||||
package: package,
|
|
||||||
};
|
|
||||||
if (status == "NotReviewed") {
|
|
||||||
var buttons =
|
|
||||||
'<button class="ignore">Ignore</button>' +
|
|
||||||
'<button class="keep">Keep</button>';
|
|
||||||
$(this).html(buttons);
|
|
||||||
$(this)
|
|
||||||
.children(".ignore")
|
|
||||||
.on("click", makeHandler(this, data, "files-ignore", "add"));
|
|
||||||
$(this)
|
|
||||||
.children(".keep")
|
|
||||||
.on("click", makeHandler(this, data, "files-keep", "add"));
|
|
||||||
} else if (status != "Added") {
|
|
||||||
$(this).html("<button>Undo review</button>");
|
|
||||||
$(this)
|
|
||||||
.children("button")
|
|
||||||
.on("click", makeHandler(this, data, filesMap[status], "remove"));
|
|
||||||
} else {
|
|
||||||
$(this).html("<button disabled>This file was added manually</button>");
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
setStatus("Initialized");
|
files.each(function (index) {
|
||||||
});
|
var package = $(this).data('package')
|
||||||
|
var filename = $(this).data('filename')
|
||||||
|
var status = $(this).data('status')
|
||||||
|
var data = {
|
||||||
|
line: filename,
|
||||||
|
package: package,
|
||||||
|
}
|
||||||
|
if (status == 'NotReviewed') {
|
||||||
|
var buttons =
|
||||||
|
'<button class="ignore">Ignore</button>' + '<button class="keep">Keep</button>'
|
||||||
|
$(this).html(buttons)
|
||||||
|
$(this).children('.ignore').on('click', makeHandler(this, data, 'files-ignore', 'add'))
|
||||||
|
$(this).children('.keep').on('click', makeHandler(this, data, 'files-keep', 'add'))
|
||||||
|
} else if (status != 'Added') {
|
||||||
|
$(this).html('<button>Undo review</button>')
|
||||||
|
$(this)
|
||||||
|
.children('button')
|
||||||
|
.on('click', makeHandler(this, data, filesMap[status], 'remove'))
|
||||||
|
} else {
|
||||||
|
$(this).html('<button disabled>This file was added manually</button>')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setStatus('Initialized')
|
||||||
|
})
|
||||||
|
@ -1,67 +1,65 @@
|
|||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
const path = require("path");
|
const path = require('path')
|
||||||
const process = require("child_process");
|
const process = require('child_process')
|
||||||
|
|
||||||
/// List of configs to clean.
|
/// List of configs to clean.
|
||||||
const configPaths = [
|
const configPaths = [
|
||||||
"../../engine/launcher/src/main/resources/META-INF/native-image/org/enso/launcher",
|
'../../engine/launcher/src/main/resources/META-INF/native-image/org/enso/launcher',
|
||||||
"../../lib/scala/project-manager/src/main/resources/META-INF/native-image/org/enso/projectmanager",
|
'../../lib/scala/project-manager/src/main/resources/META-INF/native-image/org/enso/projectmanager',
|
||||||
];
|
]
|
||||||
|
|
||||||
/// Checks if the entry is ephemeral (contains a pointer in its name).
|
/// Checks if the entry is ephemeral (contains a pointer in its name).
|
||||||
function isEntryEphemeralClass(entry) {
|
function isEntryEphemeralClass(entry) {
|
||||||
const name = entry["name"];
|
const name = entry['name']
|
||||||
if (name === undefined) {
|
if (name === undefined) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
return name.indexOf("/0x00") >= 0;
|
return name.indexOf('/0x00') >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sorts the list of entries in a predictable order.
|
/// Sorts the list of entries in a predictable order.
|
||||||
function sortEntries(entries) {
|
function sortEntries(entries) {
|
||||||
const copy = Array.from(entries);
|
const copy = Array.from(entries)
|
||||||
copy.sort((first, second) => {
|
copy.sort((first, second) => {
|
||||||
const firstName = first["name"];
|
const firstName = first['name']
|
||||||
const secondName = second["name"];
|
const secondName = second['name']
|
||||||
if (firstName !== undefined && secondName !== undefined) {
|
if (firstName !== undefined && secondName !== undefined) {
|
||||||
return firstName < secondName;
|
return firstName < secondName
|
||||||
} else if (firstName === undefined && secondName === undefined) {
|
} else if (firstName === undefined && secondName === undefined) {
|
||||||
return JSON.stringify(first) < JSON.stringify(second);
|
return JSON.stringify(first) < JSON.stringify(second)
|
||||||
} else {
|
} else {
|
||||||
return firstName === undefined;
|
return firstName === undefined
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
return copy;
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes ephemeral classes from the reflection config and ensures it has a
|
/// Removes ephemeral classes from the reflection config and ensures it has a
|
||||||
/// stable order of entries.
|
/// stable order of entries.
|
||||||
function cleanReflectionConfig(reflectConfigPath) {
|
function cleanReflectionConfig(reflectConfigPath) {
|
||||||
const data = fs.readFileSync(reflectConfigPath, "utf-8");
|
const data = fs.readFileSync(reflectConfigPath, 'utf-8')
|
||||||
const parsed = JSON.parse(data);
|
const parsed = JSON.parse(data)
|
||||||
const withoutEphemeral = parsed.filter(
|
const withoutEphemeral = parsed.filter(entry => !isEntryEphemeralClass(entry))
|
||||||
(entry) => !isEntryEphemeralClass(entry)
|
const sorted = sortEntries(withoutEphemeral)
|
||||||
);
|
const serialized = JSON.stringify(sorted)
|
||||||
const sorted = sortEntries(withoutEphemeral);
|
const hasChanges = serialized !== JSON.stringify(parsed)
|
||||||
const serialized = JSON.stringify(sorted);
|
if (hasChanges) {
|
||||||
const hasChanges = serialized !== JSON.stringify(parsed);
|
fs.writeFileSync(reflectConfigPath, serialized)
|
||||||
if (hasChanges) {
|
console.log('Rewritten ' + reflectConfigPath)
|
||||||
fs.writeFileSync(reflectConfigPath, serialized);
|
} else {
|
||||||
console.log("Rewritten " + reflectConfigPath);
|
console.log('No changes in ' + reflectConfigPath)
|
||||||
} else {
|
}
|
||||||
console.log("No changes in " + reflectConfigPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs prettier on the provided path.
|
/// Runs prettier on the provided path.
|
||||||
function runPrettier(configPath) {
|
function runPrettier(configPath) {
|
||||||
console.log("Running prettier for " + configPath);
|
console.log('Running prettier for ' + configPath)
|
||||||
process.spawn("npx", ["prettier", "--write", configPath], {
|
process.spawn('npx', ['prettier', '--write', configPath], {
|
||||||
stdio: "inherit",
|
stdio: 'inherit',
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
configPaths.forEach(function (configPath) {
|
configPaths.forEach(function (configPath) {
|
||||||
cleanReflectionConfig(path.join(configPath, "reflect-config.json"));
|
cleanReflectionConfig(path.join(configPath, 'reflect-config.json'))
|
||||||
runPrettier(configPath);
|
runPrettier(configPath)
|
||||||
});
|
})
|
||||||
|
@ -1,199 +1,195 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const express = require("express");
|
const express = require('express')
|
||||||
const crypto = require("crypto");
|
const crypto = require('crypto')
|
||||||
const path = require("path");
|
const path = require('path')
|
||||||
const os = require("os");
|
const os = require('os')
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
const fsPromises = require("fs/promises");
|
const fsPromises = require('fs/promises')
|
||||||
const multer = require("multer");
|
const multer = require('multer')
|
||||||
const compression = require("compression");
|
const compression = require('compression')
|
||||||
const yargs = require("yargs");
|
const yargs = require('yargs')
|
||||||
const semverValid = require("semver/functions/valid");
|
const semverValid = require('semver/functions/valid')
|
||||||
|
|
||||||
const argv = yargs
|
const argv = yargs
|
||||||
.usage(
|
.usage(
|
||||||
"$0",
|
'$0',
|
||||||
"Allows to host Enso libraries and editions from the local filesystem through HTTP."
|
'Allows to host Enso libraries and editions from the local filesystem through HTTP.'
|
||||||
)
|
)
|
||||||
.option("port", {
|
.option('port', {
|
||||||
description: "The port to listen on.",
|
description: 'The port to listen on.',
|
||||||
type: "number",
|
type: 'number',
|
||||||
default: 8080,
|
default: 8080,
|
||||||
})
|
})
|
||||||
.option("root", {
|
.option('root', {
|
||||||
description:
|
description:
|
||||||
"The root of the repository. It should contain a `libraries` or `editions` directory. See the documentation for more details.",
|
'The root of the repository. It should contain a `libraries` or `editions` directory. See the documentation for more details.',
|
||||||
type: "string",
|
type: 'string',
|
||||||
default: ".",
|
default: '.',
|
||||||
})
|
})
|
||||||
.option("upload", {
|
.option('upload', {
|
||||||
description:
|
description:
|
||||||
"Specifies whether to allow uploading libraries and which authentication model to choose.",
|
'Specifies whether to allow uploading libraries and which authentication model to choose.',
|
||||||
choices: ["disabled", "no-auth", "constant-token"],
|
choices: ['disabled', 'no-auth', 'constant-token'],
|
||||||
default: "disabled",
|
default: 'disabled',
|
||||||
})
|
})
|
||||||
.help()
|
.help()
|
||||||
.alias("help", "h").argv;
|
.alias('help', 'h').argv
|
||||||
|
|
||||||
const libraryRoot = path.join(argv.root, "libraries");
|
const libraryRoot = path.join(argv.root, 'libraries')
|
||||||
|
|
||||||
const app = express();
|
const app = express()
|
||||||
const tmpDir = path.join(os.tmpdir(), "enso-library-repo-uploads");
|
const tmpDir = path.join(os.tmpdir(), 'enso-library-repo-uploads')
|
||||||
const upload = multer({ dest: tmpDir });
|
const upload = multer({ dest: tmpDir })
|
||||||
app.use(compression({ filter: shouldCompress }));
|
app.use(compression({ filter: shouldCompress }))
|
||||||
|
|
||||||
/** The token to compare against for simple authentication.
|
/** The token to compare against for simple authentication.
|
||||||
*
|
*
|
||||||
* If it is not set, no authentication checks are made.
|
* If it is not set, no authentication checks are made.
|
||||||
*/
|
*/
|
||||||
let token = null;
|
let token = null
|
||||||
if (argv.upload == "disabled") {
|
if (argv.upload == 'disabled') {
|
||||||
console.log("Uploads are disabled.");
|
console.log('Uploads are disabled.')
|
||||||
} else {
|
} else {
|
||||||
app.post("/upload", upload.any(), handleUpload);
|
app.post('/upload', upload.any(), handleUpload)
|
||||||
|
|
||||||
if (argv.upload == "constant-token") {
|
if (argv.upload == 'constant-token') {
|
||||||
const envVar = "ENSO_AUTH_TOKEN";
|
const envVar = 'ENSO_AUTH_TOKEN'
|
||||||
token = process.env[envVar];
|
token = process.env[envVar]
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw `${envVar} is not defined.`;
|
throw `${envVar} is not defined.`
|
||||||
|
} else {
|
||||||
|
console.log(`Checking the ${envVar} to authorize requests.`)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`Checking the ${envVar} to authorize requests.`);
|
console.log('WARNING: Uploads are enabled without any authentication.')
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.log("WARNING: Uploads are enabled without any authentication.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get("/health", function (req, res) {
|
app.get('/health', function (req, res) {
|
||||||
res.status(200).send("OK");
|
res.status(200).send('OK')
|
||||||
});
|
})
|
||||||
|
|
||||||
app.use(express.static(argv.root));
|
app.use(express.static(argv.root))
|
||||||
|
|
||||||
let port = argv.port;
|
let port = argv.port
|
||||||
if (process.env.PORT) {
|
if (process.env.PORT) {
|
||||||
port = process.env.PORT;
|
port = process.env.PORT
|
||||||
console.log(
|
console.log(`Overriding the port to ${port} set by the PORT environment variable.`)
|
||||||
`Overriding the port to ${port} set by the PORT environment variable.`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(`Serving the repository located under ${argv.root} on port ${port}.`)
|
||||||
`Serving the repository located under ${argv.root} on port ${port}.`
|
|
||||||
);
|
|
||||||
|
|
||||||
const server = app.listen(port);
|
const server = app.listen(port)
|
||||||
|
|
||||||
function handleShutdown() {
|
function handleShutdown() {
|
||||||
console.log("Received a signal - shutting down.");
|
console.log('Received a signal - shutting down.')
|
||||||
server.close(() => {
|
server.close(() => {
|
||||||
console.log("Server terminated.");
|
console.log('Server terminated.')
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
process.on("SIGTERM", handleShutdown);
|
process.on('SIGTERM', handleShutdown)
|
||||||
process.on("SIGINT", handleShutdown);
|
process.on('SIGINT', handleShutdown)
|
||||||
|
|
||||||
/// Specifies if a particular file can be compressed in transfer, if supported.
|
/// Specifies if a particular file can be compressed in transfer, if supported.
|
||||||
function shouldCompress(req, res) {
|
function shouldCompress(req, res) {
|
||||||
if (req.path.endsWith(".yaml")) {
|
if (req.path.endsWith('.yaml')) {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return compression.filter(req, res);
|
return compression.filter(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handles upload of a library. */
|
/** Handles upload of a library. */
|
||||||
async function handleUpload(req, res) {
|
async function handleUpload(req, res) {
|
||||||
function fail(code, message) {
|
function fail(code, message) {
|
||||||
res.status(code).json({ error: message });
|
res.status(code).json({ error: message })
|
||||||
cleanFiles(req.files);
|
cleanFiles(req.files)
|
||||||
}
|
|
||||||
|
|
||||||
if (token !== null) {
|
|
||||||
const userToken = req.get("Auth-Token");
|
|
||||||
if (userToken != token) {
|
|
||||||
return fail(403, "Authorization failed.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const version = req.query.version;
|
if (token !== null) {
|
||||||
const namespace = req.query.namespace;
|
const userToken = req.get('Auth-Token')
|
||||||
const name = req.query.name;
|
if (userToken != token) {
|
||||||
|
return fail(403, 'Authorization failed.')
|
||||||
if (version === undefined || namespace == undefined || name === undefined) {
|
}
|
||||||
return fail(400, "One or more required fields were missing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isVersionValid(version)) {
|
|
||||||
return fail(400, `Invalid semver version string [${version}].`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNamespaceValid(namespace)) {
|
|
||||||
return fail(400, `Invalid username [${namespace}].`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNameValid(name)) {
|
|
||||||
return fail(400, `Invalid library name [${name}].`);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < req.files.length; ++i) {
|
|
||||||
const filename = req.files[i].originalname;
|
|
||||||
if (!isFilenameValid(filename)) {
|
|
||||||
return fail(400, `Invalid filename: ${filename}.`);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const libraryBasePath = path.join(libraryRoot, namespace, name);
|
const version = req.query.version
|
||||||
const libraryPath = path.join(libraryBasePath, version);
|
const namespace = req.query.namespace
|
||||||
|
const name = req.query.name
|
||||||
|
|
||||||
/** Finds a name for a temporary directory to move the files to,
|
if (version === undefined || namespace == undefined || name === undefined) {
|
||||||
|
return fail(400, 'One or more required fields were missing.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isVersionValid(version)) {
|
||||||
|
return fail(400, `Invalid semver version string [${version}].`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNamespaceValid(namespace)) {
|
||||||
|
return fail(400, `Invalid username [${namespace}].`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNameValid(name)) {
|
||||||
|
return fail(400, `Invalid library name [${name}].`)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < req.files.length; ++i) {
|
||||||
|
const filename = req.files[i].originalname
|
||||||
|
if (!isFilenameValid(filename)) {
|
||||||
|
return fail(400, `Invalid filename: ${filename}.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const libraryBasePath = path.join(libraryRoot, namespace, name)
|
||||||
|
const libraryPath = path.join(libraryBasePath, version)
|
||||||
|
|
||||||
|
/** Finds a name for a temporary directory to move the files to,
|
||||||
so that the upload can then be committed atomically by renaming
|
so that the upload can then be committed atomically by renaming
|
||||||
a single directory. */
|
a single directory. */
|
||||||
function findRandomTemporaryDirectory() {
|
function findRandomTemporaryDirectory() {
|
||||||
const randomName = crypto.randomBytes(32).toString("hex");
|
const randomName = crypto.randomBytes(32).toString('hex')
|
||||||
const temporaryPath = path.join(libraryBasePath, randomName);
|
const temporaryPath = path.join(libraryBasePath, randomName)
|
||||||
if (fs.existsSync(temporaryPath)) {
|
if (fs.existsSync(temporaryPath)) {
|
||||||
return findRandomTemporaryDirectory();
|
return findRandomTemporaryDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
|
return temporaryPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return temporaryPath;
|
if (fs.existsSync(libraryPath)) {
|
||||||
}
|
return fail(
|
||||||
|
409,
|
||||||
|
'A library with the given name and version ' +
|
||||||
|
'combination already exists. Versions are immutable, so you must ' +
|
||||||
|
'bump the library version when uploading a newer version.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (fs.existsSync(libraryPath)) {
|
const temporaryPath = findRandomTemporaryDirectory()
|
||||||
return fail(
|
await fsPromises.mkdir(libraryBasePath, { recursive: true })
|
||||||
409,
|
await fsPromises.mkdir(temporaryPath, { recursive: true })
|
||||||
"A library with the given name and version " +
|
|
||||||
"combination already exists. Versions are immutable, so you must " +
|
|
||||||
"bump the library version when uploading a newer version."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const temporaryPath = findRandomTemporaryDirectory();
|
console.log(`Uploading library [${namespace}.${name}:${version}].`)
|
||||||
await fsPromises.mkdir(libraryBasePath, { recursive: true });
|
try {
|
||||||
await fsPromises.mkdir(temporaryPath, { recursive: true });
|
await putFiles(temporaryPath, req.files)
|
||||||
|
await fsPromises.rename(temporaryPath, libraryPath)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Upload failed: [${error}].`)
|
||||||
|
console.error(error.stack)
|
||||||
|
return fail(500, 'Upload failed due to an internal error.')
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Uploading library [${namespace}.${name}:${version}].`);
|
console.log('Upload complete.')
|
||||||
try {
|
res.status(200).json({ message: 'Successfully uploaded the library.' })
|
||||||
await putFiles(temporaryPath, req.files);
|
|
||||||
await fsPromises.rename(temporaryPath, libraryPath);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`Upload failed: [${error}].`);
|
|
||||||
console.error(error.stack);
|
|
||||||
return fail(500, "Upload failed due to an internal error.");
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Upload complete.");
|
|
||||||
res.status(200).json({ message: "Successfully uploaded the library." });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a version complies with the semver specification.
|
/// Checks if a version complies with the semver specification.
|
||||||
function isVersionValid(version) {
|
function isVersionValid(version) {
|
||||||
return semverValid(version) !== null;
|
return semverValid(version) !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the namespace/username is valid.
|
/// Checks if the namespace/username is valid.
|
||||||
function isNamespaceValid(namespace) {
|
function isNamespaceValid(namespace) {
|
||||||
return /^[A-Za-z][a-z0-9]*$/.test(namespace) && namespace.length >= 3;
|
return /^[A-Za-z][a-z0-9]*$/.test(namespace) && namespace.length >= 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks if the library name is valid.
|
/** Checks if the library name is valid.
|
||||||
@ -203,37 +199,37 @@ function isNamespaceValid(namespace) {
|
|||||||
* for safety.
|
* for safety.
|
||||||
*/
|
*/
|
||||||
function isNameValid(name) {
|
function isNameValid(name) {
|
||||||
return /^[A-Za-z0-9_]+$/.test(name);
|
return /^[A-Za-z0-9_]+$/.test(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO [RW] for now slashes are not permitted to avoid attacks; later on at least the `meta` directory should be allowed, but not much besides that
|
// TODO [RW] for now slashes are not permitted to avoid attacks; later on at least the `meta` directory should be allowed, but not much besides that
|
||||||
/// Checks if the uploaded filename is valid.
|
/// Checks if the uploaded filename is valid.
|
||||||
function isFilenameValid(name) {
|
function isFilenameValid(name) {
|
||||||
return /^[A-Za-z0-9][A-Za-z0-9\._\-]*$/.test(name);
|
return /^[A-Za-z0-9][A-Za-z0-9\._\-]*$/.test(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedules to remove the files, if they still exist.
|
/// Schedules to remove the files, if they still exist.
|
||||||
function cleanFiles(files) {
|
function cleanFiles(files) {
|
||||||
files.forEach((file) => {
|
files.forEach(file => {
|
||||||
if (fs.existsSync(file.path)) {
|
if (fs.existsSync(file.path)) {
|
||||||
fs.unlink(file.path, (err) => {
|
fs.unlink(file.path, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(
|
console.error(
|
||||||
`Failed to remove ${file.path} ($file.originalname) from a failed upload: ${err}.`
|
`Failed to remove ${file.path} ($file.originalname) from a failed upload: ${err}.`
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the files to the provided destination directory.
|
/// Moves the files to the provided destination directory.
|
||||||
async function putFiles(directory, files) {
|
async function putFiles(directory, files) {
|
||||||
for (var i = 0; i < files.length; ++i) {
|
for (var i = 0; i < files.length; ++i) {
|
||||||
const file = files[i];
|
const file = files[i]
|
||||||
const filename = file.originalname;
|
const filename = file.originalname
|
||||||
const destination = path.join(directory, filename);
|
const destination = path.join(directory, filename)
|
||||||
await fsPromises.copyFile(file.path, destination);
|
await fsPromises.copyFile(file.path, destination)
|
||||||
await fsPromises.unlink(file.path);
|
await fsPromises.unlink(file.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user