diff --git a/.editorconfig b/.editorconfig old mode 100755 new mode 100644 index a92f7dfd..5f150f35 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,6 @@ trim_trailing_whitespace = false indent_style = space indent_size = 2 -[{**.sh,root/etc/cont-init.d/**,root/etc/services.d/**}] +[{**.sh,root/etc/s6-overlay/s6-rc.d/**,root/etc/cont-init.d/**,root/etc/services.d/**}] indent_style = space indent_size = 4 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md old mode 100755 new mode 100644 index 6b99531a..30d104f2 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,7 +6,7 @@ * Read, and fill the Pull Request template * If this is a fix for a typo (in code, documentation, or the README) please file an issue and let us sort it out. We do not need a PR * If the PR is addressing an existing issue include, closes #\, in the body of the PR commit message -* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://discord.gg/YWrKVTn) +* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://linuxserver.io/discord) ## Common files @@ -105,10 +105,10 @@ docker build \ -t linuxserver/code-server:latest . ``` -The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static` +The ARM variants can be built on x86_64 hardware and vice versa using `lscr.io/linuxserver/qemu-static` ```bash -docker run --rm --privileged multiarch/qemu-user-static:register --reset +docker run --rm --privileged lscr.io/linuxserver/qemu-static --reset ``` Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml old mode 100755 new mode 100644 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml old mode 100755 new mode 100644 index 496066b3..9e7ee210 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,7 @@ blank_issues_enabled: false contact_links: - name: Discord chat support - url: https://discord.gg/YWrKVTn + url: https://linuxserver.io/discord about: Realtime support / chat with the community and the team. - name: Discourse discussion forum diff --git a/.github/ISSUE_TEMPLATE/issue.bug.md b/.github/ISSUE_TEMPLATE/issue.bug.md deleted file mode 100755 index 6f18a3e0..00000000 --- a/.github/ISSUE_TEMPLATE/issue.bug.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve - ---- -[linuxserverurl]: https://linuxserver.io -[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl] - - - - - ------------------------------- - -## Expected Behavior - - -## Current Behavior - - -## Steps to Reproduce - - -1. -2. -3. -4. - -## Environment -**OS:** -**CPU architecture:** x86_64/arm32/arm64 -**How docker service was installed:** - - - -## Command used to create docker container (run/create/compose/screenshot) - - -## Docker logs - diff --git a/.github/ISSUE_TEMPLATE/issue.bug.yml b/.github/ISSUE_TEMPLATE/issue.bug.yml new file mode 100644 index 00000000..924f4608 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.bug.yml @@ -0,0 +1,76 @@ +# Based on the issue template +name: Bug report +description: Create a report to help us improve +title: "[BUG] " +labels: [Bug] +body: + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true + - type: textarea + attributes: + label: Current Behavior + description: Tell us what happens instead of the expected behavior. + validations: + required: true + - type: textarea + attributes: + label: Expected Behavior + description: Tell us what should happen. + validations: + required: false + - type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... + validations: + required: true + - type: textarea + attributes: + label: Environment + description: | + examples: + - **OS**: Ubuntu 20.04 + - **How docker service was installed**: distro's packagemanager + value: | + - OS: + - How docker service was installed: + render: markdown + validations: + required: false + - type: dropdown + attributes: + label: CPU architecture + options: + - x86-64 + - arm64 + validations: + required: true + - type: textarea + attributes: + label: Docker creation + description: | + Command used to create docker container + Provide your docker create/run command or compose yaml snippet, or a screenshot of settings if using a gui to create the container + render: bash + validations: + required: true + - type: textarea + attributes: + description: | + Provide a full docker log, output of "docker logs code-server" + label: Container logs + placeholder: | + Output of `docker logs code-server` + render: bash + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/issue.feature.md b/.github/ISSUE_TEMPLATE/issue.feature.md deleted file mode 100755 index 20a91fdb..00000000 --- a/.github/ISSUE_TEMPLATE/issue.feature.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project - ---- -[linuxserverurl]: https://linuxserver.io -[![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl] - -<!--- If you are new to Docker or this application our issue tracker is **ONLY** used for reporting bugs or requesting features. Please use [our discord server](https://discord.gg/YWrKVTn) for general support. ---> - -<!--- If this acts as a feature request please ask yourself if this modification is something the whole userbase will benefit from ---> -<!--- If this is a specific change for corner case functionality or plugins please look at making a Docker Mod or local script https://blog.linuxserver.io/2019/09/14/customizing-our-containers/ --> - -<!--- Provide a general summary of the request in the Title above --> - ------------------------------- - -## Desired Behavior -<!--- Tell us what should happen --> - -## Current Behavior -<!--- Tell us what happens instead of the expected behavior --> - -## Alternatives Considered -<!--- Tell us what other options you have tried or considered --> diff --git a/.github/ISSUE_TEMPLATE/issue.feature.yml b/.github/ISSUE_TEMPLATE/issue.feature.yml new file mode 100644 index 00000000..099dcdb5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.feature.yml @@ -0,0 +1,31 @@ +# Based on the issue template +name: Feature request +description: Suggest an idea for this project +title: "[FEAT] <title>" +labels: [enhancement] +body: + - type: checkboxes + attributes: + label: Is this a new feature request? + description: Please search to see if a feature request already exists. + options: + - label: I have searched the existing issues + required: true + - type: textarea + attributes: + label: Wanted change + description: Tell us what you want to happen. + validations: + required: true + - type: textarea + attributes: + label: Reason for change + description: Justify your request, why do you want it, what is the benefit. + validations: + required: true + - type: textarea + attributes: + label: Proposed code change + description: Do you have a potential code change in mind? + validations: + required: false diff --git a/.github/workflows/call_issue_pr_tracker.yml b/.github/workflows/call_issue_pr_tracker.yml new file mode 100644 index 00000000..d07cf121 --- /dev/null +++ b/.github/workflows/call_issue_pr_tracker.yml @@ -0,0 +1,19 @@ +name: Issue & PR Tracker + +on: + issues: + types: [opened,reopened,labeled,unlabeled,closed] + pull_request_target: + types: [opened,reopened,review_requested,review_request_removed,labeled,unlabeled,closed] + pull_request_review: + types: [submitted,edited,dismissed] + +permissions: + contents: read + +jobs: + manage-project: + permissions: + issues: write + uses: linuxserver/github-workflows/.github/workflows/issue-pr-tracker.yml@v1 + secrets: inherit diff --git a/.github/workflows/call_issues_cron.yml b/.github/workflows/call_issues_cron.yml new file mode 100644 index 00000000..2031b772 --- /dev/null +++ b/.github/workflows/call_issues_cron.yml @@ -0,0 +1,16 @@ +name: Mark stale issues and pull requests +on: + schedule: + - cron: '31 1 * * *' + workflow_dispatch: + +permissions: + contents: read + +jobs: + stale: + permissions: + issues: write + pull-requests: write + uses: linuxserver/github-workflows/.github/workflows/issues-cron.yml@v1 + secrets: inherit diff --git a/.github/workflows/external_trigger.yml b/.github/workflows/external_trigger.yml index 83854498..c62e1beb 100644 --- a/.github/workflows/external_trigger.yml +++ b/.github/workflows/external_trigger.yml @@ -3,24 +3,42 @@ name: External Trigger Main on: workflow_dispatch: +permissions: + contents: read + jobs: external-trigger-master: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.3.3 + - uses: actions/checkout@v4.1.1 - name: External Trigger if: github.ref == 'refs/heads/master' + env: + SKIP_EXTERNAL_TRIGGER: ${{ vars.SKIP_EXTERNAL_TRIGGER }} run: | - if [ -n "${{ secrets.PAUSE_EXTERNAL_TRIGGER_CODE_SERVER_MASTER }}" ]; then - echo "**** Github secret PAUSE_EXTERNAL_TRIGGER_CODE_SERVER_MASTER is set; skipping trigger. ****" + printf "# External trigger for docker-code-server\n\n" >> $GITHUB_STEP_SUMMARY + if grep -q "^code-server_master_" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`code-server_master_\`; will skip trigger if version matches." >> $GITHUB_STEP_SUMMARY + elif grep -q "^code-server_master" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`code-server_master\`; skipping trigger." >> $GITHUB_STEP_SUMMARY + exit 0 + fi + echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY + echo "> External trigger running off of master branch. To disable this trigger, add \`code-server_master\` into the Github organizational variable \`SKIP_EXTERNAL_TRIGGER\`." >> $GITHUB_STEP_SUMMARY + printf "\n## Retrieving external version\n\n" >> $GITHUB_STEP_SUMMARY + EXT_RELEASE=$(curl -u ${{ secrets.CR_USER }}:${{ secrets.CR_PAT }} -sX GET https://api.github.com/repos/coder/code-server/releases/latest | jq -r '.tag_name' | sed 's|^v||') + echo "Type is \`custom_version_command\`" >> $GITHUB_STEP_SUMMARY + if grep -q "^code-server_master_${EXT_RELEASE}" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` matches current external release; skipping trigger." >> $GITHUB_STEP_SUMMARY exit 0 fi - echo "**** External trigger running off of master branch. To disable this trigger, set a Github secret named \"PAUSE_EXTERNAL_TRIGGER_CODE_SERVER_MASTER\". ****" - echo "**** Retrieving external version ****" - EXT_RELEASE=$(curl -sX GET https://registry.yarnpkg.com/code-server | jq -r '."dist-tags".latest' | sed 's|^|v|') if [ -z "${EXT_RELEASE}" ] || [ "${EXT_RELEASE}" == "null" ]; then - echo "**** Can't retrieve external version, exiting ****" + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Can't retrieve external version, exiting" >> $GITHUB_STEP_SUMMARY FAILURE_REASON="Can't retrieve external version for code-server branch master" GHA_TRIGGER_URL="https://github.com/linuxserver/docker-code-server/actions/runs/${{ github.run_id }}" curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 16711680, @@ -28,65 +46,102 @@ jobs: "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} exit 1 fi - EXT_RELEASE=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') - echo "**** External version: ${EXT_RELEASE} ****" - echo "**** Retrieving last pushed version ****" + EXT_RELEASE_SANITIZED=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') + echo "Sanitized external version: \`${EXT_RELEASE_SANITIZED}\`" >> $GITHUB_STEP_SUMMARY + echo "Retrieving last pushed version" >> $GITHUB_STEP_SUMMARY image="linuxserver/code-server" tag="latest" token=$(curl -sX GET \ "https://ghcr.io/token?scope=repository%3Alinuxserver%2Fcode-server%3Apull" \ | jq -r '.token') - multidigest=$(curl -s \ - --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/manifests/${tag}" \ - | jq -r 'first(.manifests[].digest)') - digest=$(curl -s \ + multidigest=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.index.v1+json" \ + --header "Authorization: Bearer ${token}" \ + "https://ghcr.io/v2/${image}/manifests/${tag}") + if jq -e '.layers // empty' <<< "${multidigest}" >/dev/null 2>&1; then + # If there's a layer element it's a single-arch manifest so just get that digest + digest=$(jq -r '.config.digest' <<< "${multidigest}") + else + # Otherwise it's multi-arch or has manifest annotations + if jq -e '.manifests[]?.annotations // empty' <<< "${multidigest}" >/dev/null 2>&1; then + # Check for manifest annotations and delete if found + multidigest=$(jq 'del(.manifests[] | select(.annotations))' <<< "${multidigest}") + fi + if [[ $(jq '.manifests | length' <<< "${multidigest}") -gt 1 ]]; then + # If there's still more than one digest, it's multi-arch + multidigest=$(jq -r ".manifests[] | select(.platform.architecture == \"amd64\").digest?" <<< "${multidigest}") + else + # Otherwise it's single arch + multidigest=$(jq -r ".manifests[].digest?" <<< "${multidigest}") + fi + if digest=$(curl -s \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.manifest.v1+json" \ --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/manifests/${multidigest}" \ - | jq -r '.config.digest') + "https://ghcr.io/v2/${image}/manifests/${multidigest}"); then + digest=$(jq -r '.config.digest' <<< "${digest}"); + fi + fi image_info=$(curl -sL \ --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/blobs/${digest}" \ - | jq -r '.container_config') + "https://ghcr.io/v2/${image}/blobs/${digest}") + if [[ $(echo $image_info | jq -r '.container_config') == "null" ]]; then + image_info=$(echo $image_info | jq -r '.config') + else + image_info=$(echo $image_info | jq -r '.container_config') + fi IMAGE_RELEASE=$(echo ${image_info} | jq -r '.Labels.build_version' | awk '{print $3}') IMAGE_VERSION=$(echo ${IMAGE_RELEASE} | awk -F'-ls' '{print $1}') if [ -z "${IMAGE_VERSION}" ]; then - echo "**** Can't retrieve last pushed version, exiting ****" + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "Can't retrieve last pushed version, exiting" >> $GITHUB_STEP_SUMMARY FAILURE_REASON="Can't retrieve last pushed version for code-server tag latest" curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 16711680, "description": "**Trigger Failed** \n**Reason:** '"${FAILURE_REASON}"' \n"}], "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} exit 1 fi - echo "**** Last pushed version: ${IMAGE_VERSION} ****" - if [ "${EXT_RELEASE}" == "${IMAGE_VERSION}" ]; then - echo "**** Version ${EXT_RELEASE} already pushed, exiting ****" + echo "Last pushed version: \`${IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY + if [ "${EXT_RELEASE_SANITIZED}" == "${IMAGE_VERSION}" ]; then + echo "Sanitized version \`${EXT_RELEASE_SANITIZED}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY exit 0 elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then - echo "**** New version ${EXT_RELEASE} found; but there already seems to be an active build on Jenkins; exiting ****" + echo "New version \`${EXT_RELEASE}\` found; but there already seems to be an active build on Jenkins; exiting" >> $GITHUB_STEP_SUMMARY exit 0 else - echo "**** New version ${EXT_RELEASE} found; old version was ${IMAGE_VERSION}. Triggering new build ****" - response=$(curl -iX POST \ - https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/master/buildWithParameters?PACKAGE_CHECK=false \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") - echo "**** Jenkins job queue url: ${response%$'\r'} ****" - echo "**** Sleeping 10 seconds until job starts ****" - sleep 10 - buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') - buildurl="${buildurl%$'\r'}" - echo "**** Jenkins job build url: ${buildurl} ****" - echo "**** Attempting to change the Jenkins job description ****" - curl -iX POST \ - "${buildurl}submitDescription" \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ - --data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ - --data-urlencode "Submit=Submit" - echo "**** Notifying Discord ****" - TRIGGER_REASON="A version change was detected for code-server tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE}" - curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, - "description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}], - "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + if [[ "${artifacts_found}" == "false" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> New version detected, but not all artifacts are published yet; skipping trigger" >> $GITHUB_STEP_SUMMARY + FAILURE_REASON="New version ${EXT_RELEASE} for code-server tag latest is detected, however not all artifacts are uploaded to upstream release yet. Will try again later." + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Trigger Failed** \n**Reason:** '"${FAILURE_REASON}"' \n"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + else + printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY + echo "New sanitized version \`${EXT_RELEASE_SANITIZED}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY + if [[ "${artifacts_found}" == "true" ]]; then + echo "All artifacts seem to be uploaded." >> $GITHUB_STEP_SUMMARY + fi + response=$(curl -iX POST \ + https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/master/buildWithParameters?PACKAGE_CHECK=false \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") + echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY + echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY + sleep 10 + buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') + buildurl="${buildurl%$'\r'}" + echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY + echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY + curl -iX POST \ + "${buildurl}submitDescription" \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ + --data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ + --data-urlencode "Submit=Submit" + echo "**** Notifying Discord ****" + TRIGGER_REASON="A version change was detected for code-server tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE_SANITIZED}" + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + fi fi diff --git a/.github/workflows/external_trigger_scheduler.yml b/.github/workflows/external_trigger_scheduler.yml index 21082001..94943e5a 100644 --- a/.github/workflows/external_trigger_scheduler.yml +++ b/.github/workflows/external_trigger_scheduler.yml @@ -2,42 +2,47 @@ name: External Trigger Scheduler on: schedule: - - cron: '41 * * * *' + - cron: '32 * * * *' workflow_dispatch: +permissions: + contents: read + jobs: external-trigger-scheduler: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.3.3 + - uses: actions/checkout@v4.1.1 with: fetch-depth: '0' - name: External Trigger Scheduler run: | - echo "**** Branches found: ****" - git for-each-ref --format='%(refname:short)' refs/remotes - echo "**** Pulling the yq docker image ****" - docker pull ghcr.io/linuxserver/yq - for br in $(git for-each-ref --format='%(refname:short)' refs/remotes) + printf "# External trigger scheduler for docker-code-server\n\n" >> $GITHUB_STEP_SUMMARY + printf "Found the branches:\n\n%s\n" "$(git for-each-ref --format='- %(refname:lstrip=3)' refs/remotes)" >> $GITHUB_STEP_SUMMARY + for br in $(git for-each-ref --format='%(refname:lstrip=3)' refs/remotes) do - br=$(echo "$br" | sed 's|origin/||g') - echo "**** Evaluating branch ${br} ****" - ls_branch=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/jenkins-vars.yml \ - | docker run --rm -i --entrypoint yq ghcr.io/linuxserver/yq -r .ls_branch) - if [ "$br" == "$ls_branch" ]; then - echo "**** Branch ${br} appears to be live; checking workflow. ****" + if [[ "${br}" == "HEAD" ]]; then + printf "\nSkipping %s.\n" ${br} >> $GITHUB_STEP_SUMMARY + continue + fi + printf "\n## Evaluating \`%s\`\n\n" ${br} >> $GITHUB_STEP_SUMMARY + ls_jenkins_vars=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/jenkins-vars.yml) + ls_branch=$(echo "${ls_jenkins_vars}" | yq -r '.ls_branch') + ls_trigger=$(echo "${ls_jenkins_vars}" | yq -r '.external_type') + if [[ "${br}" == "${ls_branch}" ]] && [[ "${ls_trigger}" != "os" ]]; then + echo "Branch appears to be live and trigger is not os; checking workflow." >> $GITHUB_STEP_SUMMARY if curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/.github/workflows/external_trigger.yml > /dev/null 2>&1; then - echo "**** Workflow exists. Triggering external trigger workflow for branch ${br} ****." + echo "Triggering external trigger workflow for branch." >> $GITHUB_STEP_SUMMARY curl -iX POST \ -H "Authorization: token ${{ secrets.CR_PAT }}" \ -H "Accept: application/vnd.github.v3+json" \ -d "{\"ref\":\"refs/heads/${br}\"}" \ https://api.github.com/repos/linuxserver/docker-code-server/actions/workflows/external_trigger.yml/dispatches else - echo "**** Workflow doesn't exist; skipping trigger. ****" + echo "Skipping branch due to no external trigger workflow present." >> $GITHUB_STEP_SUMMARY fi else - echo "**** ${br} appears to be a dev branch; skipping trigger. ****" + echo "Skipping branch due to being detected as dev branch or having no external version." >> $GITHUB_STEP_SUMMARY fi done diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml old mode 100755 new mode 100644 index 7d36ef02..f63a55e8 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -2,12 +2,18 @@ name: Greetings on: [pull_request_target, issues] +permissions: + contents: read + jobs: greeting: + permissions: + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/first-interaction@v1 with: - issue-message: 'Thanks for opening your first issue here! Be sure to follow the [bug](https://github.com/linuxserver/docker-code-server/blob/master/.github/ISSUE_TEMPLATE/issue.bug.md) or [feature](https://github.com/linuxserver/docker-code-server/blob/master/.github/ISSUE_TEMPLATE/issue.feature.md) issue templates!' + issue-message: 'Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.' pr-message: 'Thanks for opening this pull request! Be sure to follow the [pull request template](https://github.com/linuxserver/docker-code-server/blob/master/.github/PULL_REQUEST_TEMPLATE.md)!' repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/package_trigger.yml b/.github/workflows/package_trigger.yml deleted file mode 100644 index 3199c2d0..00000000 --- a/.github/workflows/package_trigger.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Package Trigger Main - -on: - workflow_dispatch: - -jobs: - package-trigger-master: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2.3.3 - - - name: Package Trigger - if: github.ref == 'refs/heads/master' - run: | - if [ -n "${{ secrets.PAUSE_PACKAGE_TRIGGER_CODE_SERVER_MASTER }}" ]; then - echo "**** Github secret PAUSE_PACKAGE_TRIGGER_CODE_SERVER_MASTER is set; skipping trigger. ****" - exit 0 - fi - if [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then - echo "**** There already seems to be an active build on Jenkins; skipping package trigger ****" - exit 0 - fi - echo "**** Package trigger running off of master branch. To disable, set a Github secret named \"PAUSE_PACKAGE_TRIGGER_CODE_SERVER_MASTER\". ****" - response=$(curl -iX POST \ - https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/master/buildWithParameters?PACKAGE_CHECK=true \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") - echo "**** Jenkins job queue url: ${response%$'\r'} ****" - echo "**** Sleeping 10 seconds until job starts ****" - sleep 10 - buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') - buildurl="${buildurl%$'\r'}" - echo "**** Jenkins job build url: ${buildurl} ****" - echo "**** Attempting to change the Jenkins job description ****" - curl -iX POST \ - "${buildurl}submitDescription" \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ - --data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ - --data-urlencode "Submit=Submit" diff --git a/.github/workflows/package_trigger_scheduler.yml b/.github/workflows/package_trigger_scheduler.yml index 3ca70a24..d0982556 100644 --- a/.github/workflows/package_trigger_scheduler.yml +++ b/.github/workflows/package_trigger_scheduler.yml @@ -2,49 +2,102 @@ name: Package Trigger Scheduler on: schedule: - - cron: '00 12 * * 0' + - cron: '0 20 * * 6' workflow_dispatch: +permissions: + contents: read + jobs: package-trigger-scheduler: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.3.3 + - uses: actions/checkout@v4.1.1 with: fetch-depth: '0' - name: Package Trigger Scheduler + env: + SKIP_PACKAGE_TRIGGER: ${{ vars.SKIP_PACKAGE_TRIGGER }} run: | - echo "**** Branches found: ****" - git for-each-ref --format='%(refname:short)' refs/remotes - echo "**** Pulling the yq docker image ****" - docker pull ghcr.io/linuxserver/yq - for br in $(git for-each-ref --format='%(refname:short)' refs/remotes) + printf "# Package trigger scheduler for docker-code-server\n\n" >> $GITHUB_STEP_SUMMARY + printf "Found the branches:\n\n%s\n" "$(git for-each-ref --format='- %(refname:lstrip=3)' refs/remotes)" >> $GITHUB_STEP_SUMMARY + for br in $(git for-each-ref --format='%(refname:lstrip=3)' refs/remotes) do - br=$(echo "$br" | sed 's|origin/||g') - echo "**** Evaluating branch ${br} ****" - ls_branch=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/jenkins-vars.yml \ - | docker run --rm -i --entrypoint yq ghcr.io/linuxserver/yq -r .ls_branch) - if [ "${br}" == "${ls_branch}" ]; then - echo "**** Branch ${br} appears to be live; checking workflow. ****" - if curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/.github/workflows/package_trigger.yml > /dev/null 2>&1; then - echo "**** Workflow exists. Triggering package trigger workflow for branch ${br}. ****" - triggered_branches="${triggered_branches}${br} " - curl -iX POST \ - -H "Authorization: token ${{ secrets.CR_PAT }}" \ - -H "Accept: application/vnd.github.v3+json" \ - -d "{\"ref\":\"refs/heads/${br}\"}" \ - https://api.github.com/repos/linuxserver/docker-code-server/actions/workflows/package_trigger.yml/dispatches - sleep 30 + if [[ "${br}" == "HEAD" ]]; then + printf "\nSkipping %s.\n" ${br} >> $GITHUB_STEP_SUMMARY + continue + fi + printf "\n## Evaluating \`%s\`\n\n" ${br} >> $GITHUB_STEP_SUMMARY + JENKINS_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/jenkins-vars.yml) + if ! curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/Jenkinsfile >/dev/null 2>&1; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> No Jenkinsfile found. Branch is either deprecated or is an early dev branch." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [[ "${br}" == $(yq -r '.ls_branch' <<< "${JENKINS_VARS}") ]]; then + echo "Branch appears to be live; checking workflow." >> $GITHUB_STEP_SUMMARY + README_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-code-server/${br}/readme-vars.yml) + if [[ $(yq -r '.project_deprecation_status' <<< "${README_VARS}") == "true" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Branch appears to be deprecated; skipping trigger." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [[ $(yq -r '.skip_package_check' <<< "${JENKINS_VARS}") == "true" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Skipping branch ${br} due to \`skip_package_check\` being set in \`jenkins-vars.yml\`." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif grep -q "^code-server_${br}" <<< "${SKIP_PACKAGE_TRIGGER}"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_PACKAGE_TRIGGER\` contains \`code-server_${br}\`; skipping trigger." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/${br}/lastBuild/api/json | jq -r '.building' 2>/dev/null) == "true" ]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> There already seems to be an active build on Jenkins; skipping package trigger for ${br}" >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " else - echo "**** Workflow doesn't exist; skipping trigger. ****" + echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY + echo "> Triggering package trigger for branch ${br}" >> $GITHUB_STEP_SUMMARY + printf "> To disable, add \`code-server_%s\` into the Github organizational variable \`SKIP_PACKAGE_TRIGGER\`.\n\n" "${br}" >> $GITHUB_STEP_SUMMARY + triggered_branches="${triggered_branches}${br} " + response=$(curl -iX POST \ + https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-code-server/job/${br}/buildWithParameters?PACKAGE_CHECK=true \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") + if [[ -z "${response}" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Jenkins build could not be triggered. Skipping branch." + continue + fi + echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY + echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY + sleep 10 + buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') + buildurl="${buildurl%$'\r'}" + echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY + echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY + if ! curl -ifX POST \ + "${buildurl}submitDescription" \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ + --data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ + --data-urlencode "Submit=Submit"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Unable to change the Jenkins job description." + fi + sleep 20 fi else - echo "**** ${br} appears to be a dev branch; skipping trigger. ****" + echo "Skipping branch ${br} due to being detected as dev branch." >> $GITHUB_STEP_SUMMARY fi done - echo "**** Package check build(s) triggered for branch(es): ${triggered_branches} ****" - echo "**** Notifying Discord ****" - curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, - "description": "**Package Check Build(s) Triggered for code-server** \n**Branch(es):** '"${triggered_branches}"' \n**Build URL:** '"https://ci.linuxserver.io/blue/organizations/jenkins/Docker-Pipeline-Builders%2Fdocker-code-server/activity/"' \n"}], - "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + if [[ -n "${triggered_branches}" ]] || [[ -n "${skipped_branches}" ]]; then + if [[ -n "${triggered_branches}" ]]; then + NOTIFY_BRANCHES="**Triggered:** ${triggered_branches} \n" + NOTIFY_BUILD_URL="**Build URL:** https://ci.linuxserver.io/blue/organizations/jenkins/Docker-Pipeline-Builders%2Fdocker-code-server/activity/ \n" + echo "**** Package check build(s) triggered for branch(es): ${triggered_branches} ****" + fi + if [[ -n "${skipped_branches}" ]]; then + NOTIFY_BRANCHES="${NOTIFY_BRANCHES}**Skipped:** ${skipped_branches} \n" + fi + echo "**** Notifying Discord ****" + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Package Check Build(s) for code-server** \n'"${NOTIFY_BRANCHES}"''"${NOTIFY_BUILD_URL}"'"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + fi diff --git a/.github/workflows/permissions.yml b/.github/workflows/permissions.yml new file mode 100644 index 00000000..02e1bdb9 --- /dev/null +++ b/.github/workflows/permissions.yml @@ -0,0 +1,12 @@ +name: Permission check +on: + pull_request_target: + paths: + - '**/run' + - '**/finish' + - '**/check' + - 'root/migrations/*' + +jobs: + permission_check: + uses: linuxserver/github-workflows/.github/workflows/init-svc-executable-permissions.yml@v1 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100755 index 3b3846ee..00000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Mark stale issues and pull requests - -on: - schedule: - - cron: "30 1 * * *" - -jobs: - stale: - - runs-on: ubuntu-latest - - steps: - - uses: actions/stale@v3 - with: - stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions." - stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions." - stale-issue-label: 'no-issue-activity' - stale-pr-label: 'no-pr-activity' - days-before-stale: 30 - days-before-close: 365 - exempt-issue-labels: 'awaiting-approval,work-in-progress' - exempt-pr-labels: 'awaiting-approval,work-in-progress' - repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index 6e6a0243..9ac98d92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ -FROM ghcr.io/linuxserver/baseimage-ubuntu:bionic +# syntax=docker/dockerfile:1 + +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble # set version label ARG BUILD_DATE @@ -8,54 +10,34 @@ LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DA LABEL maintainer="aptalca" # environment settings +ARG DEBIAN_FRONTEND="noninteractive" ENV HOME="/config" RUN \ - echo "**** install node repo ****" && \ - apt-get update && \ - apt-get install -y \ - gnupg && \ - curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ - echo 'deb https://deb.nodesource.com/node_14.x bionic main' \ - > /etc/apt/sources.list.d/nodesource.list && \ - curl -s https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ - echo 'deb https://dl.yarnpkg.com/debian/ stable main' \ - > /etc/apt/sources.list.d/yarn.list && \ - echo "**** install build dependencies ****" && \ - apt-get update && \ - apt-get install -y \ - build-essential \ - libx11-dev \ - libxkbfile-dev \ - libsecret-1-dev \ - pkg-config && \ echo "**** install runtime dependencies ****" && \ + apt-get update && \ apt-get install -y \ git \ - jq \ + libatomic1 \ nano \ net-tools \ - nodejs \ - sudo \ - yarn && \ + sudo && \ echo "**** install code-server ****" && \ if [ -z ${CODE_RELEASE+x} ]; then \ - CODE_RELEASE=$(curl -sX GET https://registry.yarnpkg.com/code-server \ - | jq -r '."dist-tags".latest' | sed 's|^|v|'); \ + CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest \ + | awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||'); \ fi && \ - CODE_VERSION=$(echo "$CODE_RELEASE" | awk '{print substr($1,2); }') && \ - yarn config set network-timeout 600000 -g && \ - yarn --production --verbose --frozen-lockfile global add code-server@"$CODE_VERSION" && \ - yarn cache clean && \ + mkdir -p /app/code-server && \ + curl -o \ + /tmp/code-server.tar.gz -L \ + "https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-amd64.tar.gz" && \ + tar xf /tmp/code-server.tar.gz -C \ + /app/code-server --strip-components=1 && \ + printf "Linuxserver.io version: ${VERSION}\nBuild-date: ${BUILD_DATE}" > /build_version && \ echo "**** clean up ****" && \ - apt-get purge --auto-remove -y \ - build-essential \ - libx11-dev \ - libxkbfile-dev \ - libsecret-1-dev \ - pkg-config && \ apt-get clean && \ rm -rf \ + /config/* \ /tmp/* \ /var/lib/apt/lists/* \ /var/tmp/* diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index bd4e2099..6e052507 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -1,4 +1,6 @@ -FROM ghcr.io/linuxserver/baseimage-ubuntu:arm64v8-bionic +# syntax=docker/dockerfile:1 + +FROM ghcr.io/linuxserver/baseimage-ubuntu:arm64v8-noble # set version label ARG BUILD_DATE @@ -8,54 +10,34 @@ LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DA LABEL maintainer="aptalca" # environment settings +ARG DEBIAN_FRONTEND="noninteractive" ENV HOME="/config" RUN \ - echo "**** install node repo ****" && \ - apt-get update && \ - apt-get install -y \ - gnupg && \ - curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ - echo 'deb https://deb.nodesource.com/node_14.x bionic main' \ - > /etc/apt/sources.list.d/nodesource.list && \ - curl -s https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ - echo 'deb https://dl.yarnpkg.com/debian/ stable main' \ - > /etc/apt/sources.list.d/yarn.list && \ - echo "**** install build dependencies ****" && \ - apt-get update && \ - apt-get install -y \ - build-essential \ - libx11-dev \ - libxkbfile-dev \ - libsecret-1-dev \ - pkg-config && \ echo "**** install runtime dependencies ****" && \ + apt-get update && \ apt-get install -y \ git \ - jq \ + libatomic1 \ nano \ net-tools \ - nodejs \ - sudo \ - yarn && \ + sudo && \ echo "**** install code-server ****" && \ if [ -z ${CODE_RELEASE+x} ]; then \ - CODE_RELEASE=$(curl -sX GET https://registry.yarnpkg.com/code-server \ - | jq -r '."dist-tags".latest' | sed 's|^|v|'); \ + CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest \ + | awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||'); \ fi && \ - CODE_VERSION=$(echo "$CODE_RELEASE" | awk '{print substr($1,2); }') && \ - yarn config set network-timeout 600000 -g && \ - yarn --production --verbose --frozen-lockfile global add code-server@"$CODE_VERSION" && \ - yarn cache clean && \ + mkdir -p /app/code-server && \ + curl -o \ + /tmp/code-server.tar.gz -L \ + "https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-arm64.tar.gz" && \ + tar xf /tmp/code-server.tar.gz -C \ + /app/code-server --strip-components=1 && \ + printf "Linuxserver.io version: ${VERSION}\nBuild-date: ${BUILD_DATE}" > /build_version && \ echo "**** clean up ****" && \ - apt-get purge --auto-remove -y \ - build-essential \ - libx11-dev \ - libxkbfile-dev \ - libsecret-1-dev \ - pkg-config && \ apt-get clean && \ rm -rf \ + /config/* \ /tmp/* \ /var/lib/apt/lists/* \ /var/tmp/* diff --git a/Dockerfile.armhf b/Dockerfile.armhf deleted file mode 100644 index 86a97b3a..00000000 --- a/Dockerfile.armhf +++ /dev/null @@ -1,67 +0,0 @@ -FROM ghcr.io/linuxserver/baseimage-ubuntu:arm32v7-bionic - -# set version label -ARG BUILD_DATE -ARG VERSION -ARG CODE_RELEASE -LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" -LABEL maintainer="aptalca" - -# environment settings -ENV HOME="/config" - -RUN \ - echo "**** install node repo ****" && \ - apt-get update && \ - apt-get install -y \ - gnupg && \ - curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ - echo 'deb https://deb.nodesource.com/node_14.x bionic main' \ - > /etc/apt/sources.list.d/nodesource.list && \ - curl -s https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ - echo 'deb https://dl.yarnpkg.com/debian/ stable main' \ - > /etc/apt/sources.list.d/yarn.list && \ - echo "**** install build dependencies ****" && \ - apt-get update && \ - apt-get install -y \ - build-essential \ - libx11-dev \ - libxkbfile-dev \ - libsecret-1-dev \ - pkg-config && \ - echo "**** install runtime dependencies ****" && \ - apt-get install -y \ - git \ - jq \ - nano \ - net-tools \ - nodejs \ - sudo \ - yarn && \ - echo "**** install code-server ****" && \ - if [ -z ${CODE_RELEASE+x} ]; then \ - CODE_RELEASE=$(curl -sX GET https://registry.yarnpkg.com/code-server \ - | jq -r '."dist-tags".latest' | sed 's|^|v|'); \ - fi && \ - CODE_VERSION=$(echo "$CODE_RELEASE" | awk '{print substr($1,2); }') && \ - yarn config set network-timeout 600000 -g && \ - yarn --production --verbose --frozen-lockfile global add code-server@"$CODE_VERSION" && \ - yarn cache clean && \ - echo "**** clean up ****" && \ - apt-get purge --auto-remove -y \ - build-essential \ - libx11-dev \ - libxkbfile-dev \ - libsecret-1-dev \ - pkg-config && \ - apt-get clean && \ - rm -rf \ - /tmp/* \ - /var/lib/apt/lists/* \ - /var/tmp/* - -# add local files -COPY /root / - -# ports and volumes -EXPOSE 8443 diff --git a/Jenkinsfile b/Jenkinsfile index 75bfe0c4..e49fc044 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { } // Input to determine if this is a package check parameters { - string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') + string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') } // Configuration for the variables used for this specific repo environment { @@ -16,7 +16,9 @@ pipeline { GITHUB_TOKEN=credentials('498b4638-2d02-4ce5-832d-8a57d01d97ab') GITLAB_TOKEN=credentials('b6f0f1dd-6952-4cf6-95d1-9c06380283f0') GITLAB_NAMESPACE=credentials('gitlab-namespace-id') - SCARF_TOKEN=credentials('scarf_api_key') + DOCKERHUB_TOKEN=credentials('docker-hub-ci-pat') + QUAYIO_API_TOKEN=credentials('quayio-repo-api-token') + GIT_SIGNING_KEY=credentials('484fbca6-9a4f-455e-b9e3-97ac98785f5f') CONTAINER_NAME = 'code-server' BUILD_VERSION_ARG = 'CODE_RELEASE' LS_USER = 'linuxserver' @@ -31,18 +33,50 @@ pipeline { CI_PORT='8443' CI_SSL='false' CI_DELAY='120' - CI_DOCKERENV='TZ=US/Pacific' - CI_AUTH='user:password' + CI_DOCKERENV='' + CI_AUTH='' CI_WEBPATH='' } stages { + stage("Set git config"){ + steps{ + sh '''#!/bin/bash + cat ${GIT_SIGNING_KEY} > /config/.ssh/id_sign + chmod 600 /config/.ssh/id_sign + ssh-keygen -y -f /config/.ssh/id_sign > /config/.ssh/id_sign.pub + echo "Using $(ssh-keygen -lf /config/.ssh/id_sign) to sign commits" + git config --global gpg.format ssh + git config --global user.signingkey /config/.ssh/id_sign + git config --global commit.gpgsign true + ''' + } + } // Setup all the basic environment variables needed for the build stage("Set ENV Variables base"){ steps{ + echo "Running on node: ${NODE_NAME}" + sh '''#! /bin/bash + echo "Pruning builder" + docker builder prune -f --builder container || : + containers=$(docker ps -q) + if [[ -n "${containers}" ]]; then + BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') + for container in ${containers}; do + if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then + echo "skipping buildx container in docker stop" + else + echo "Stopping container ${container}" + docker stop ${container} + fi + done + fi + docker system prune -f --volumes || : + docker image prune -af || : + ''' script{ env.EXIT_STATUS = '' env.LS_RELEASE = sh( - script: '''docker run --rm ghcr.io/linuxserver/alexeiled-skopeo sh -c 'skopeo inspect docker://docker.io/'${DOCKERHUB_IMAGE}':latest 2>/dev/null' | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', + script: '''docker run --rm quay.io/skopeo/stable:v1 inspect docker://ghcr.io/${LS_USER}/${CONTAINER_NAME}:latest 2>/dev/null | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', returnStdout: true).trim() env.LS_RELEASE_NOTES = sh( script: '''cat readme-vars.yml | awk -F \\" '/date: "[0-9][0-9].[0-9][0-9].[0-9][0-9]:/ {print $4;exit;}' | sed -E ':a;N;$!ba;s/\\r{0,1}\\n/\\\\n/g' ''', @@ -53,11 +87,20 @@ pipeline { env.COMMIT_SHA = sh( script: '''git rev-parse HEAD''', returnStdout: true).trim() + env.GH_DEFAULT_BRANCH = sh( + script: '''git remote show origin | grep "HEAD branch:" | sed 's|.*HEAD branch: ||' ''', + returnStdout: true).trim() env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/commit/' + env.GIT_COMMIT env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/' env.PULL_REQUEST = env.CHANGE_ID - env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig ./.github/CONTRIBUTING.md ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/config.yml ./.github/ISSUE_TEMPLATE/issue.bug.md ./.github/ISSUE_TEMPLATE/issue.feature.md ./.github/PULL_REQUEST_TEMPLATE.md ./.github/workflows/external_trigger_scheduler.yml ./.github/workflows/greetings.yml ./.github/workflows/package_trigger_scheduler.yml ./.github/workflows/stale.yml ./.github/workflows/external_trigger.yml ./.github/workflows/package_trigger.yml' + env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig ./.github/CONTRIBUTING.md ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/config.yml ./.github/ISSUE_TEMPLATE/issue.bug.yml ./.github/ISSUE_TEMPLATE/issue.feature.yml ./.github/PULL_REQUEST_TEMPLATE.md ./.github/workflows/external_trigger_scheduler.yml ./.github/workflows/greetings.yml ./.github/workflows/package_trigger_scheduler.yml ./.github/workflows/call_issue_pr_tracker.yml ./.github/workflows/call_issues_cron.yml ./.github/workflows/permissions.yml ./.github/workflows/external_trigger.yml' + if ( env.SYFT_IMAGE_TAG == null ) { + env.SYFT_IMAGE_TAG = 'latest' + } } + echo "Using syft image tag ${SYFT_IMAGE_TAG}" + sh '''#! /bin/bash + echo "The default github branch detected as ${GH_DEFAULT_BRANCH}" ''' script{ env.LS_RELEASE_NUMBER = sh( script: '''echo ${LS_RELEASE} |sed 's/^.*-ls//g' ''', @@ -104,7 +147,7 @@ pipeline { steps{ script{ env.EXT_RELEASE = sh( - script: ''' curl -sX GET https://registry.yarnpkg.com/code-server | jq -r '."dist-tags".latest' | sed 's|^|v|' ''', + script: ''' curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest | jq -r '.tag_name' | sed 's|^v||' ''', returnStdout: true).trim() env.RELEASE_LINK = 'custom_command' } @@ -115,15 +158,14 @@ pipeline { steps{ script{ env.EXT_RELEASE_CLEAN = sh( - script: '''echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g' ''', + script: '''echo ${EXT_RELEASE} | sed 's/[~,%@+;:/ ]//g' ''', returnStdout: true).trim() - env.SEMVER = (new Date()).format('YYYY.MM.dd') - def semver = env.EXT_RELEASE_CLEAN =~ /(\d+)\.(\d+)\.(\d+)$/ + def semver = env.EXT_RELEASE_CLEAN =~ /(\d+)\.(\d+)\.(\d+)/ if (semver.find()) { env.SEMVER = "${semver[0][1]}.${semver[0][2]}.${semver[0][3]}" } else { - semver = env.EXT_RELEASE_CLEAN =~ /(\d+)\.(\d+)(?:\.(\d+))?(.*)$/ + semver = env.EXT_RELEASE_CLEAN =~ /(\d+)\.(\d+)(?:\.(\d+))?(.*)/ if (semver.find()) { if (semver[0][3]) { env.SEMVER = "${semver[0][1]}.${semver[0][2]}.${semver[0][3]}" @@ -133,7 +175,15 @@ pipeline { } } - println("SEMVER: ${env.SEMVER}") + if (env.SEMVER != null) { + if (BRANCH_NAME != "${env.GH_DEFAULT_BRANCH}") { + env.SEMVER = "${env.SEMVER}-${BRANCH_NAME}" + } + println("SEMVER: ${env.SEMVER}") + } else { + println("No SEMVER detected") + } + } } } @@ -150,13 +200,15 @@ pipeline { env.GITLABIMAGE = 'registry.gitlab.com/linuxserver.io/' + env.LS_REPO + '/' + env.CONTAINER_NAME env.QUAYIMAGE = 'quay.io/linuxserver.io/' + env.CONTAINER_NAME if (env.MULTIARCH == 'true') { - env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + '|arm32v7-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER } else { env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER } env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'latest' } } } @@ -173,7 +225,7 @@ pipeline { env.GITLABIMAGE = 'registry.gitlab.com/linuxserver.io/' + env.LS_REPO + '/lsiodev-' + env.CONTAINER_NAME env.QUAYIMAGE = 'quay.io/linuxserver.io/lsiodev-' + env.CONTAINER_NAME if (env.MULTIARCH == 'true') { - env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '|arm32v7-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA } else { env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA } @@ -181,6 +233,8 @@ pipeline { env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/' + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -196,15 +250,17 @@ pipeline { env.GITLABIMAGE = 'registry.gitlab.com/linuxserver.io/' + env.LS_REPO + '/lspipepr-' + env.CONTAINER_NAME env.QUAYIMAGE = 'quay.io/linuxserver.io/lspipepr-' + env.CONTAINER_NAME if (env.MULTIARCH == 'true') { - env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + '|arm32v7-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + env.CI_TAGS = 'amd64-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '-pr-' + env.PULL_REQUEST + '|arm64v8-' + env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '-pr-' + env.PULL_REQUEST } else { - env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + env.CI_TAGS = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '-pr-' + env.PULL_REQUEST } - env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST - env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-pr-' + env.PULL_REQUEST + env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '-pr-' + env.PULL_REQUEST + env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA + '-pr-' + env.PULL_REQUEST env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/' + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -221,19 +277,18 @@ pipeline { script{ env.SHELLCHECK_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/shellcheck-result.xml' } - sh '''curl -sL https://raw.githubusercontent.com/linuxserver/docker-shellcheck/master/checkrun.sh | /bin/bash''' + sh '''curl -sL https://raw.githubusercontent.com/linuxserver/docker-jenkins-builder/master/checkrun.sh | /bin/bash''' sh '''#! /bin/bash - set -e - docker pull ghcr.io/linuxserver/lsiodev-spaces-file-upload:latest docker run --rm \ - -e DESTINATION=\"${IMAGE}/${META_TAG}/shellcheck-result.xml\" \ - -e FILE_NAME="shellcheck-result.xml" \ - -e MIMETYPE="text/xml" \ - -v ${WORKSPACE}:/mnt \ - -e SECRET_KEY=\"${S3_SECRET}\" \ - -e ACCESS_KEY=\"${S3_KEY}\" \ - -t ghcr.io/linuxserver/lsiodev-spaces-file-upload:latest \ - python /upload.py''' + -v ${WORKSPACE}:/mnt \ + -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ + -e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \ + ghcr.io/linuxserver/baseimage-alpine:3.23 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ + apk add --no-cache python3 && \ + python3 -m venv /lsiopy && \ + pip install --no-cache-dir -U pip && \ + pip install --no-cache-dir s3cmd && \ + s3cmd put --no-preserve --acl-public -m text/xml /mnt/shellcheck-result.xml s3://ci-tests.linuxserver.io/${IMAGE}/${META_TAG}/shellcheck-result.xml" || :''' } } } @@ -251,8 +306,15 @@ pipeline { set -e TEMPDIR=$(mktemp -d) docker pull ghcr.io/linuxserver/jenkins-builder:latest - docker run --rm -e CONTAINER_NAME=${CONTAINER_NAME} -e GITHUB_BRANCH=master -v ${TEMPDIR}:/ansible/jenkins ghcr.io/linuxserver/jenkins-builder:latest - # Stage 1 - Jenkinsfile update + # Cloned repo paths for templating: + # ${TEMPDIR}/docker-${CONTAINER_NAME}: Cloned branch master of ${LS_USER}/${LS_REPO} for running the jenkins builder on + # ${TEMPDIR}/repo/${LS_REPO}: Cloned branch master of ${LS_USER}/${LS_REPO} for commiting various templated file changes and pushing back to Github + # ${TEMPDIR}/docs/docker-documentation: Cloned docs repo for pushing docs updates to Github + # ${TEMPDIR}/unraid/docker-templates: Cloned docker-templates repo to check for logos + # ${TEMPDIR}/unraid/templates: Cloned templates repo for commiting unraid template changes and pushing back to Github + git clone --branch master --depth 1 https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/docker-${CONTAINER_NAME} + docker run --rm -v ${TEMPDIR}/docker-${CONTAINER_NAME}:/tmp -e LOCAL=true -e PUID=$(id -u) -e PGID=$(id -g) ghcr.io/linuxserver/jenkins-builder:latest + echo "Starting Stage 1 - Jenkinsfile update" if [[ "$(md5sum Jenkinsfile | awk '{ print $1 }')" != "$(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/Jenkinsfile | awk '{ print $1 }')" ]]; then mkdir -p ${TEMPDIR}/repo git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/repo/${LS_REPO} @@ -261,16 +323,17 @@ pipeline { cp ${TEMPDIR}/docker-${CONTAINER_NAME}/Jenkinsfile ${TEMPDIR}/repo/${LS_REPO}/ git add Jenkinsfile git commit -m 'Bot Updating Templated Files' - git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git --all + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} - echo "Updating Jenkinsfile" + echo "Updating Jenkinsfile and exiting build, new one will trigger based on commit" rm -Rf ${TEMPDIR} exit 0 else echo "Jenkinsfile is up to date." fi - # Stage 2 - Delete old templates - OLD_TEMPLATES=".github/ISSUE_TEMPLATE.md" + echo "Starting Stage 2 - Delete old templates" + OLD_TEMPLATES=".github/ISSUE_TEMPLATE.md .github/ISSUE_TEMPLATE/issue.bug.md .github/ISSUE_TEMPLATE/issue.feature.md .github/workflows/call_invalid_helper.yml .github/workflows/stale.yml .github/workflows/package_trigger.yml" for i in ${OLD_TEMPLATES}; do if [[ -f "${i}" ]]; then TEMPLATES_TO_DELETE="${i} ${TEMPLATES_TO_DELETE}" @@ -285,15 +348,45 @@ pipeline { git rm "${i}" done git commit -m 'Bot Updating Templated Files' - git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git --all + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} - echo "Deleting old templates" + echo "Deleting old/deprecated templates and exiting build, new one will trigger based on commit" rm -Rf ${TEMPDIR} exit 0 else echo "No templates to delete" fi - # Stage 3 - Update templates + echo "Starting Stage 2.5 - Update init diagram" + if ! grep -q 'init_diagram:' readme-vars.yml; then + echo "Adding the key 'init_diagram' to readme-vars.yml" + sed -i '\\|^#.*changelog.*$|d' readme-vars.yml + sed -i 's|^changelogs:|# init diagram\\ninit_diagram:\\n\\n# changelog\\nchangelogs:|' readme-vars.yml + fi + mkdir -p ${TEMPDIR}/d2 + docker run --rm -v ${TEMPDIR}/d2:/output -e PUID=$(id -u) -e PGID=$(id -g) -e RAW="true" ghcr.io/linuxserver/d2-builder:latest ${CONTAINER_NAME}:latest + ls -al ${TEMPDIR}/d2 + yq -ei ".init_diagram |= load_str(\\"${TEMPDIR}/d2/${CONTAINER_NAME}-latest.d2\\")" readme-vars.yml + if [[ $(md5sum readme-vars.yml | cut -c1-8) != $(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/readme-vars.yml | cut -c1-8) ]]; then + echo "'init_diagram' has been updated. Updating repo and exiting build, new one will trigger based on commit." + mkdir -p ${TEMPDIR}/repo + git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/repo/${LS_REPO} + cd ${TEMPDIR}/repo/${LS_REPO} + git checkout -f master + cp ${WORKSPACE}/readme-vars.yml ${TEMPDIR}/repo/${LS_REPO}/readme-vars.yml + git add readme-vars.yml + git commit -m 'Bot Updating Templated Files' + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Updating templates and exiting build, new one will trigger based on commit" + rm -Rf ${TEMPDIR} + exit 0 + else + echo "false" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Init diagram is unchanged" + fi + echo "Starting Stage 3 - Update templates" CURRENTHASH=$(grep -hs ^ ${TEMPLATED_FILES} | md5sum | cut -c1-8) cd ${TEMPDIR}/docker-${CONTAINER_NAME} NEWHASH=$(grep -hs ^ ${TEMPLATED_FILES} | md5sum | cut -c1-8) @@ -306,45 +399,104 @@ pipeline { mkdir -p ${TEMPDIR}/repo/${LS_REPO}/.github/workflows mkdir -p ${TEMPDIR}/repo/${LS_REPO}/.github/ISSUE_TEMPLATE cp --parents ${TEMPLATED_FILES} ${TEMPDIR}/repo/${LS_REPO}/ || : + cp --parents readme-vars.yml ${TEMPDIR}/repo/${LS_REPO}/ || : cd ${TEMPDIR}/repo/${LS_REPO}/ if ! grep -q '.jenkins-external' .gitignore 2>/dev/null; then echo ".jenkins-external" >> .gitignore git add .gitignore fi - git add ${TEMPLATED_FILES} + git add readme-vars.yml ${TEMPLATED_FILES} git commit -m 'Bot Updating Templated Files' - git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git --all + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Updating templates and exiting build, new one will trigger based on commit" + rm -Rf ${TEMPDIR} + exit 0 else echo "false" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "No templates to update" fi - mkdir -p ${TEMPDIR}/gitbook - git clone https://github.com/linuxserver/docker-documentation.git ${TEMPDIR}/gitbook/docker-documentation - if [[ ("${BRANCH_NAME}" == "master") || ("${BRANCH_NAME}" == "main") ]] && [[ (! -f ${TEMPDIR}/gitbook/docker-documentation/images/docker-${CONTAINER_NAME}.md) || ("$(md5sum ${TEMPDIR}/gitbook/docker-documentation/images/docker-${CONTAINER_NAME}.md | awk '{ print $1 }')" != "$(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/docker-${CONTAINER_NAME}.md | awk '{ print $1 }')") ]]; then - cp ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/docker-${CONTAINER_NAME}.md ${TEMPDIR}/gitbook/docker-documentation/images/ - cd ${TEMPDIR}/gitbook/docker-documentation/ - git add images/docker-${CONTAINER_NAME}.md + echo "Starting Stage 4 - External repo updates: Docs, Unraid Template and Readme Sync to Docker Hub" + mkdir -p ${TEMPDIR}/docs + git clone --depth=1 https://github.com/linuxserver/docker-documentation.git ${TEMPDIR}/docs/docker-documentation + if [[ "${BRANCH_NAME}" == "${GH_DEFAULT_BRANCH}" ]] && [[ (! -f ${TEMPDIR}/docs/docker-documentation/docs/images/docker-${CONTAINER_NAME}.md) || ("$(md5sum ${TEMPDIR}/docs/docker-documentation/docs/images/docker-${CONTAINER_NAME}.md | awk '{ print $1 }')" != "$(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/docker-${CONTAINER_NAME}.md | awk '{ print $1 }')") ]]; then + cp ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/docker-${CONTAINER_NAME}.md ${TEMPDIR}/docs/docker-documentation/docs/images/ + cd ${TEMPDIR}/docs/docker-documentation + GH_DOCS_DEFAULT_BRANCH=$(git remote show origin | grep "HEAD branch:" | sed 's|.*HEAD branch: ||') + git add docs/images/docker-${CONTAINER_NAME}.md + echo "Updating docs repo" git commit -m 'Bot Updating Documentation' - git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/docker-documentation.git --all + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/docker-documentation.git ${GH_DOCS_DEFAULT_BRANCH} --rebase + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/docker-documentation.git ${GH_DOCS_DEFAULT_BRANCH} || \ + (MAXWAIT="10" && echo "Push to docs failed, trying again in ${MAXWAIT} seconds" && \ + sleep $((RANDOM % MAXWAIT)) && \ + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/docker-documentation.git ${GH_DOCS_DEFAULT_BRANCH} --rebase && \ + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/docker-documentation.git ${GH_DOCS_DEFAULT_BRANCH}) + else + echo "Docs update not needed, skipping" fi mkdir -p ${TEMPDIR}/unraid - git clone https://github.com/linuxserver/docker-templates.git ${TEMPDIR}/unraid/docker-templates - git clone https://github.com/linuxserver/templates.git ${TEMPDIR}/unraid/templates + git clone --depth=1 https://github.com/linuxserver/docker-templates.git ${TEMPDIR}/unraid/docker-templates + git clone --depth=1 https://github.com/linuxserver/templates.git ${TEMPDIR}/unraid/templates if [[ -f ${TEMPDIR}/unraid/docker-templates/linuxserver.io/img/${CONTAINER_NAME}-logo.png ]]; then sed -i "s|master/linuxserver.io/img/linuxserver-ls-logo.png|master/linuxserver.io/img/${CONTAINER_NAME}-logo.png|" ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/${CONTAINER_NAME}.xml + elif [[ -f ${TEMPDIR}/unraid/docker-templates/linuxserver.io/img/${CONTAINER_NAME}-icon.png ]]; then + sed -i "s|master/linuxserver.io/img/linuxserver-ls-logo.png|master/linuxserver.io/img/${CONTAINER_NAME}-icon.png|" ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/${CONTAINER_NAME}.xml fi - if [[ ("${BRANCH_NAME}" == "master") || ("${BRANCH_NAME}" == "main") ]] && [[ (! -f ${TEMPDIR}/unraid/templates/unraid/${CONTAINER_NAME}.xml) || ("$(md5sum ${TEMPDIR}/unraid/templates/unraid/${CONTAINER_NAME}.xml | awk '{ print $1 }')" != "$(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/${CONTAINER_NAME}.xml | awk '{ print $1 }')") ]]; then + if [[ "${BRANCH_NAME}" == "${GH_DEFAULT_BRANCH}" ]] && [[ (! -f ${TEMPDIR}/unraid/templates/unraid/${CONTAINER_NAME}.xml) || ("$(md5sum ${TEMPDIR}/unraid/templates/unraid/${CONTAINER_NAME}.xml | awk '{ print $1 }')" != "$(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/${CONTAINER_NAME}.xml | awk '{ print $1 }')") ]]; then + echo "Updating Unraid template" cd ${TEMPDIR}/unraid/templates/ - if grep -wq "${CONTAINER_NAME}" ${TEMPDIR}/unraid/templates/unraid/ignore.list; then - echo "Image is on the ignore list, removing Unraid template" - git rm unraid/${CONTAINER_NAME}.xml || : - git commit -m 'Bot Removing Deprecated Unraid Template' || : + GH_TEMPLATES_DEFAULT_BRANCH=$(git remote show origin | grep "HEAD branch:" | sed 's|.*HEAD branch: ||') + if grep -wq "^${CONTAINER_NAME}$" ${TEMPDIR}/unraid/templates/unraid/ignore.list && [[ -f ${TEMPDIR}/unraid/templates/unraid/deprecated/${CONTAINER_NAME}.xml ]]; then + echo "Image is on the ignore list, and already in the deprecation folder." + elif grep -wq "^${CONTAINER_NAME}$" ${TEMPDIR}/unraid/templates/unraid/ignore.list; then + echo "Image is on the ignore list, marking Unraid template as deprecated" + cp ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/${CONTAINER_NAME}.xml ${TEMPDIR}/unraid/templates/unraid/ + git add -u unraid/${CONTAINER_NAME}.xml + git mv unraid/${CONTAINER_NAME}.xml unraid/deprecated/${CONTAINER_NAME}.xml || : + git commit -m 'Bot Moving Deprecated Unraid Template' || : else cp ${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/${CONTAINER_NAME}.xml ${TEMPDIR}/unraid/templates/unraid/ git add unraid/${CONTAINER_NAME}.xml git commit -m 'Bot Updating Unraid Template' fi - git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/templates.git --all + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/templates.git ${GH_TEMPLATES_DEFAULT_BRANCH} --rebase + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/templates.git ${GH_TEMPLATES_DEFAULT_BRANCH} || \ + (MAXWAIT="10" && echo "Push to unraid templates failed, trying again in ${MAXWAIT} seconds" && \ + sleep $((RANDOM % MAXWAIT)) && \ + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/templates.git ${GH_TEMPLATES_DEFAULT_BRANCH} --rebase && \ + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/linuxserver/templates.git ${GH_TEMPLATES_DEFAULT_BRANCH}) + else + echo "No updates to Unraid template needed, skipping" + fi + if [[ "${BRANCH_NAME}" == "${GH_DEFAULT_BRANCH}" ]]; then + if [[ $(cat ${TEMPDIR}/docker-${CONTAINER_NAME}/README.md | wc -m) -gt 25000 ]]; then + echo "Readme is longer than 25,000 characters. Syncing the lite version to Docker Hub" + DH_README_SYNC_PATH="${TEMPDIR}/docker-${CONTAINER_NAME}/.jenkins-external/README.lite" + else + echo "Syncing readme to Docker Hub" + DH_README_SYNC_PATH="${TEMPDIR}/docker-${CONTAINER_NAME}/README.md" + fi + if curl -s https://hub.docker.com/v2/namespaces/${DOCKERHUB_IMAGE%%/*}/repositories/${DOCKERHUB_IMAGE##*/}/tags | jq -r '.message' | grep -q 404; then + echo "Docker Hub endpoint doesn't exist. Creating endpoint first." + DH_TOKEN=$(curl -d '{"username":"linuxserverci", "password":"'${DOCKERHUB_TOKEN}'"}' -H "Content-Type: application/json" -X POST https://hub.docker.com/v2/users/login | jq -r '.token') + curl -s \ + -H "Authorization: JWT ${DH_TOKEN}" \ + -H "Content-Type: application/json" \ + -X POST \ + -d '{"name":"'${DOCKERHUB_IMAGE##*/}'", "namespace":"'${DOCKERHUB_IMAGE%%/*}'"}' \ + https://hub.docker.com/v2/repositories/ || : + fi + DH_TOKEN=$(curl -d '{"username":"linuxserverci", "password":"'${DOCKERHUB_TOKEN}'"}' -H "Content-Type: application/json" -X POST https://hub.docker.com/v2/users/login | jq -r '.token') + curl -s \ + -H "Authorization: JWT ${DH_TOKEN}" \ + -H "Content-Type: application/json" \ + -X PATCH \ + -d "{\\"full_description\\":$(jq -Rsa . ${DH_README_SYNC_PATH})}" \ + https://hub.docker.com/v2/repositories/${DOCKERHUB_IMAGE} || : + else + echo "Not the default Github branch. Skipping readme sync to Docker Hub." fi rm -Rf ${TEMPDIR}''' script{ @@ -370,66 +522,48 @@ pipeline { } } } - /* ####################### - GitLab Mirroring - ####################### */ - // Ping into Gitlab to mirror this repo and have a registry endpoint - stage("GitLab Mirror"){ + // If this is a master build check the S6 service file perms + stage("Check S6 Service file Permissions"){ when { + branch "master" + environment name: 'CHANGE_ID', value: '' environment name: 'EXIT_STATUS', value: '' } - steps{ - sh '''curl -H "Content-Type: application/json" -H "Private-Token: ${GITLAB_TOKEN}" -X POST https://gitlab.com/api/v4/projects \ - -d '{"namespace_id":'${GITLAB_NAMESPACE}',\ - "name":"'${LS_REPO}'", - "mirror":true,\ - "import_url":"https://github.com/linuxserver/'${LS_REPO}'.git",\ - "issues_access_level":"disabled",\ - "merge_requests_access_level":"disabled",\ - "repository_access_level":"enabled",\ - "visibility":"public"}' ''' - } + steps { + script{ + sh '''#! /bin/bash + WRONG_PERM=$(find ./ -path "./.git" -prune -o \\( -name "run" -o -name "finish" -o -name "check" \\) -not -perm -u=x,g=x,o=x -print) + if [[ -n "${WRONG_PERM}" ]]; then + echo "The following S6 service files are missing the executable bit; canceling the faulty build: ${WRONG_PERM}" + exit 1 + else + echo "S6 service file perms look good." + fi ''' + } + } } /* ####################### - Scarf.sh package registry + GitLab Mirroring and Quay.io Repo Visibility ####################### */ - // Add package to Scarf.sh and set permissions - stage("Scarf.sh package registry"){ + // Ping into Gitlab to mirror this repo and have a registry endpoint & mark this repo on Quay.io as public + stage("GitLab Mirror and Quay.io Visibility"){ when { - branch "master" environment name: 'EXIT_STATUS', value: '' } steps{ - sh '''#! /bin/bash - set -e - PACKAGE_UUID=$(curl -X GET -H "Authorization: Bearer ${SCARF_TOKEN}" https://scarf.sh/api/v1/packages | jq -r '.[] | select(.name=="linuxserver/code-server") | .uuid') - if [ -z "${PACKAGE_UUID}" ]; then - echo "Adding package to Scarf.sh" - PACKAGE_UUID=$(curl -sX POST https://scarf.sh/api/v1/packages \ - -H "Authorization: Bearer ${SCARF_TOKEN}" \ - -H "Content-Type: application/json" \ - -d '{"name":"linuxserver/code-server",\ - "shortDescription":"example description",\ - "libraryType":"docker",\ - "website":"https://github.com/linuxserver/docker-code-server",\ - "backendUrl":"https://ghcr.io/linuxserver/code-server",\ - "publicUrl":"https://lscr.io/linuxserver/code-server"}' \ - | jq -r .uuid) - else - echo "Package already exists on Scarf.sh" - fi - echo "Setting permissions on Scarf.sh for package ${PACKAGE_UUID}" - curl -X POST https://scarf.sh/api/v1/packages/${PACKAGE_UUID}/permissions \ - -H "Authorization: Bearer ${SCARF_TOKEN}" \ - -H "Content-Type: application/json" \ - -d '[{"userQuery":"Spad","permissionLevel":"admin"},\ - {"userQuery":"roxedus","permissionLevel":"admin"},\ - {"userQuery":"nemchik","permissionLevel":"admin"},\ - {"userQuery":"driz","permissionLevel":"admin"},\ - {"userQuery":"aptalca","permissionLevel":"admin"},\ - {"userQuery":"saarg","permissionLevel":"admin"},\ - {"userQuery":"Stark","permissionLevel":"admin"}]' - ''' + sh '''curl -H "Content-Type: application/json" -H "Private-Token: ${GITLAB_TOKEN}" -X POST https://gitlab.com/api/v4/projects \ + -d '{"namespace_id":'${GITLAB_NAMESPACE}',\ + "name":"'${LS_REPO}'", + "mirror":true,\ + "import_url":"https://github.com/linuxserver/'${LS_REPO}'.git",\ + "issues_access_level":"disabled",\ + "merge_requests_access_level":"disabled",\ + "repository_access_level":"enabled",\ + "visibility":"public"}' ''' + sh '''curl -H "Private-Token: ${GITLAB_TOKEN}" -X PUT "https://gitlab.com/api/v4/projects/Linuxserver.io%2F${LS_REPO}" \ + -d "mirror=true&import_url=https://github.com/linuxserver/${LS_REPO}.git" ''' + sh '''curl -H "Content-Type: application/json" -H "Authorization: Bearer ${QUAYIO_API_TOKEN}" -X POST "https://quay.io/api/v1/repository${QUAYIMAGE/quay.io/}/changevisibility" \ + -d '{"visibility":"public"}' ||: ''' } } /* ############### @@ -445,7 +579,8 @@ pipeline { } steps { echo "Running on node: ${NODE_NAME}" - sh "docker build \ + sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile" + sh "docker buildx build \ --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ --label \"org.opencontainers.image.authors=linuxserver.io\" \ --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-code-server/packages\" \ @@ -457,9 +592,47 @@ pipeline { --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ --label \"org.opencontainers.image.title=Code-server\" \ - --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome.\" \ - --no-cache --pull -t ${IMAGE}:${META_TAG} \ + --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome. \" \ + --no-cache --pull -t ${IMAGE}:${META_TAG} --platform=linux/amd64 \ + --provenance=true --sbom=true --builder=container --load \ --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } + done + fi + ''' + } + } } } // Build MultiArch Docker containers for push to LS Repo @@ -475,7 +648,8 @@ pipeline { stage('Build X86') { steps { echo "Running on node: ${NODE_NAME}" - sh "docker build \ + sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile" + sh "docker buildx build \ --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ --label \"org.opencontainers.image.authors=linuxserver.io\" \ --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-code-server/packages\" \ @@ -487,43 +661,47 @@ pipeline { --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ --label \"org.opencontainers.image.title=Code-server\" \ - --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome.\" \ - --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} \ + --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome. \" \ + --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} --platform=linux/amd64 \ + --provenance=true --sbom=true --builder=container --load \ --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." - } - } - stage('Build ARMHF') { - agent { - label 'ARMHF' - } - steps { - echo "Running on node: ${NODE_NAME}" - echo 'Logging into Github' sh '''#! /bin/bash - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:amd64-${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + done ''' - sh "docker build \ - --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ - --label \"org.opencontainers.image.authors=linuxserver.io\" \ - --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-code-server/packages\" \ - --label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-code-server\" \ - --label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-code-server\" \ - --label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ - --label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.vendor=linuxserver.io\" \ - --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ - --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.title=Code-server\" \ - --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome.\" \ - --no-cache --pull -f Dockerfile.armhf -t ${IMAGE}:arm32v7-${META_TAG} \ - --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." - sh "docker tag ${IMAGE}:arm32v7-${META_TAG} ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER}" - retry(5) { - sh "docker push ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER}" + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } + done + fi + ''' + } } - sh '''docker rmi \ - ${IMAGE}:arm32v7-${META_TAG} \ - ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} || :''' } } stage('Build ARM64') { @@ -532,11 +710,8 @@ pipeline { } steps { echo "Running on node: ${NODE_NAME}" - echo 'Logging into Github' - sh '''#! /bin/bash - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - ''' - sh "docker build \ + sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile.aarch64" + sh "docker buildx build \ --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ --label \"org.opencontainers.image.authors=linuxserver.io\" \ --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-code-server/packages\" \ @@ -548,16 +723,54 @@ pipeline { --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ --label \"org.opencontainers.image.title=Code-server\" \ - --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome.\" \ - --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} \ + --label \"org.opencontainers.image.description=[Code-server](https://coder.com) is VS Code running on a remote server, accessible through the browser. - Code on your Chromebook, tablet, and laptop with a consistent dev environment. - If you have a Windows or Mac workstation, more easily develop for Linux. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Preserve battery life when you're on the go. - All intensive computation runs on your server. - You're no longer running excess instances of Chrome. \" \ + --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} --platform=linux/arm64 \ + --provenance=true --sbom=true --builder=container --load \ --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." - sh "docker tag ${IMAGE}:arm64v8-${META_TAG} ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" - retry(5) { - sh "docker push ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:arm64v8-${META_TAG} ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } + done + fi + ''' + } } - sh '''docker rmi \ - ${IMAGE}:arm64v8-${META_TAG} \ - ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || :''' + sh '''#! /bin/bash + containers=$(docker ps -aq) + if [[ -n "${containers}" ]]; then + docker stop ${containers} + fi + docker system prune -f --volumes || : + docker image prune -af || : + ''' } } } @@ -573,31 +786,17 @@ pipeline { sh '''#! /bin/bash set -e TEMPDIR=$(mktemp -d) - if [ "${MULTIARCH}" == "true" ] && [ "${PACKAGE_CHECK}" == "false" ]; then + if [ "${MULTIARCH}" == "true" ] && [ "${PACKAGE_CHECK}" != "true" ]; then LOCAL_CONTAINER=${IMAGE}:amd64-${META_TAG} else LOCAL_CONTAINER=${IMAGE}:${META_TAG} fi - if [ "${DIST_IMAGE}" == "alpine" ]; then - docker run --rm --entrypoint '/bin/sh' -v ${TEMPDIR}:/tmp ${LOCAL_CONTAINER} -c '\ - apk info -v > /tmp/package_versions.txt && \ - sort -o /tmp/package_versions.txt /tmp/package_versions.txt && \ - chmod 777 /tmp/package_versions.txt' - elif [ "${DIST_IMAGE}" == "ubuntu" ]; then - docker run --rm --entrypoint '/bin/sh' -v ${TEMPDIR}:/tmp ${LOCAL_CONTAINER} -c '\ - apt list -qq --installed | sed "s#/.*now ##g" | cut -d" " -f1 > /tmp/package_versions.txt && \ - sort -o /tmp/package_versions.txt /tmp/package_versions.txt && \ - chmod 777 /tmp/package_versions.txt' - elif [ "${DIST_IMAGE}" == "fedora" ]; then - docker run --rm --entrypoint '/bin/sh' -v ${TEMPDIR}:/tmp ${LOCAL_CONTAINER} -c '\ - rpm -qa > /tmp/package_versions.txt && \ - sort -o /tmp/package_versions.txt /tmp/package_versions.txt && \ - chmod 777 /tmp/package_versions.txt' - elif [ "${DIST_IMAGE}" == "arch" ]; then - docker run --rm --entrypoint '/bin/sh' -v ${TEMPDIR}:/tmp ${LOCAL_CONTAINER} -c '\ - pacman -Q > /tmp/package_versions.txt && \ - chmod 777 /tmp/package_versions.txt' - fi + touch ${TEMPDIR}/package_versions.txt + docker run --rm \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + -v ${TEMPDIR}:/tmp \ + ghcr.io/anchore/syft:${SYFT_IMAGE_TAG} \ + ${LOCAL_CONTAINER} -o table=/tmp/package_versions.txt NEW_PACKAGE_TAG=$(md5sum ${TEMPDIR}/package_versions.txt | cut -c1-8 ) echo "Package tag sha from current packages in buit container is ${NEW_PACKAGE_TAG} comparing to old ${PACKAGE_TAG} from github" if [ "${NEW_PACKAGE_TAG}" != "${PACKAGE_TAG}" ]; then @@ -608,7 +807,8 @@ pipeline { wait git add package_versions.txt git commit -m 'Bot Updating Package Versions' - git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git --all + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master echo "true" > /tmp/packages-${COMMIT_SHA}-${BUILD_NUMBER} echo "Package tag updated, stopping build process" else @@ -632,13 +832,6 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - sh '''#! /bin/bash - echo "Packages were updated. Cleaning up the image and exiting." - if [ "${MULTIARCH}" == "true" ] && [ "${PACKAGE_CHECK}" == "false" ]; then - docker rmi ${IMAGE}:amd64-${META_TAG} - else - docker rmi ${IMAGE}:${META_TAG} - fi''' script{ env.EXIT_STATUS = 'ABORTED' } @@ -656,13 +849,6 @@ pipeline { } } steps { - sh '''#! /bin/bash - echo "There are no package updates. Cleaning up the image and exiting." - if [ "${MULTIARCH}" == "true" ] && [ "${PACKAGE_CHECK}" == "false" ]; then - docker rmi ${IMAGE}:amd64-${META_TAG} - else - docker rmi ${IMAGE}:${META_TAG} - fi''' script{ env.EXIT_STATUS = 'ABORTED' } @@ -684,23 +870,31 @@ pipeline { ]) { script{ env.CI_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/index.html' + env.CI_JSON_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/report.json' } sh '''#! /bin/bash set -e - docker pull ghcr.io/linuxserver/ci:latest + if grep -q 'docker-baseimage' <<< "${LS_REPO}"; then + echo "Detected baseimage, setting LSIO_FIRST_PARTY=true" + if [ -n "${CI_DOCKERENV}" ]; then + CI_DOCKERENV="LSIO_FIRST_PARTY=true|${CI_DOCKERENV}" + else + CI_DOCKERENV="LSIO_FIRST_PARTY=true" + fi + fi + docker pull ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} if [ "${MULTIARCH}" == "true" ]; then - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} - docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm32v7-${META_TAG} + docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} fi docker run --rm \ --shm-size=1gb \ -v /var/run/docker.sock:/var/run/docker.sock \ -e IMAGE=\"${IMAGE}\" \ - -e DELAY_START=\"${CI_DELAY}\" \ + -e DOCKER_LOGS_TIMEOUT=\"${CI_DELAY}\" \ -e TAGS=\"${CI_TAGS}\" \ -e META_TAG=\"${META_TAG}\" \ + -e RELEASE_TAG=\"latest\" \ -e PORT=\"${CI_PORT}\" \ -e SSL=\"${CI_SSL}\" \ -e BASE=\"${DIST_IMAGE}\" \ @@ -710,10 +904,12 @@ pipeline { -e WEB_SCREENSHOT=\"${CI_WEB}\" \ -e WEB_AUTH=\"${CI_AUTH}\" \ -e WEB_PATH=\"${CI_WEBPATH}\" \ - -e DO_REGION="ams3" \ - -e DO_BUCKET="lsio-ci" \ - -t ghcr.io/linuxserver/ci:latest \ - python /ci/ci.py''' + -e NODE_NAME=\"${NODE_NAME}\" \ + -e SYFT_IMAGE_TAG=\"${CI_SYFT_IMAGE_TAG:-${SYFT_IMAGE_TAG}}\" \ + -e COMMIT_SHA=\"${COMMIT_SHA}\" \ + -e BUILD_NUMBER=\"${BUILD_NUMBER}\" \ + -t ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} \ + python3 test_build.py''' } } } @@ -727,48 +923,25 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', - usernameVariable: 'DOCKERUSER', - passwordVariable: 'DOCKERPASS' - ], - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: 'Quay.io-Robot', - usernameVariable: 'QUAYUSER', - passwordVariable: 'QUAYPASS' - ] - ]) { - retry(5) { - sh '''#! /bin/bash - set -e - echo $DOCKERPASS | docker login -u $DOCKERUSER --password-stdin - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin - echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin - for PUSHIMAGE in "${GITHUBIMAGE}" "${GITLABIMAGE}" "${QUAYIMAGE}" "${IMAGE}"; do - docker tag ${IMAGE}:${META_TAG} ${PUSHIMAGE}:${META_TAG} - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:latest - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${EXT_RELEASE_TAG} - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${SEMVER} - docker push ${PUSHIMAGE}:latest - docker push ${PUSHIMAGE}:${META_TAG} - docker push ${PUSHIMAGE}:${EXT_RELEASE_TAG} - docker push ${PUSHIMAGE}:${SEMVER} - done - ''' - } + retry_backoff(5,5) { sh '''#! /bin/bash - for DELETEIMAGE in "${GITHUBIMAGE}" "${GITLABIMAGE}" "${QUAYIMAGE}" "${IMAGE}"; do - docker rmi \ - ${DELETEIMAGE}:${META_TAG} \ - ${DELETEIMAGE}:${EXT_RELEASE_TAG} \ - ${DELETEIMAGE}:latest \ - ${DELETEIMAGE}:${SEMVER} || : + set -e + for PUSHIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + [[ ${PUSHIMAGE%%/*} =~ \\. ]] && PUSHIMAGEPLUS="${PUSHIMAGE}" || PUSHIMAGEPLUS="docker.io/${PUSHIMAGE}" + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${PUSHIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then + CACHEIMAGE=${i} + fi + done + docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + fi done - ''' + ''' } } } @@ -779,101 +952,41 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', - usernameVariable: 'DOCKERUSER', - passwordVariable: 'DOCKERPASS' - ], - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: 'Quay.io-Robot', - usernameVariable: 'QUAYUSER', - passwordVariable: 'QUAYPASS' - ] - ]) { - retry(5) { - sh '''#! /bin/bash - set -e - echo $DOCKERPASS | docker login -u $DOCKERUSER --password-stdin - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin - echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin - if [ "${CI}" == "false" ]; then - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} - docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm32v7-${META_TAG} - docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} - fi - for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do - docker tag ${IMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} - docker tag ${IMAGE}:arm32v7-${META_TAG} ${MANIFESTIMAGE}:arm32v7-${META_TAG} - docker tag ${IMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-latest - docker tag ${MANIFESTIMAGE}:arm32v7-${META_TAG} ${MANIFESTIMAGE}:arm32v7-latest - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-latest - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} - docker tag ${MANIFESTIMAGE}:arm32v7-${META_TAG} ${MANIFESTIMAGE}:arm32v7-${EXT_RELEASE_TAG} - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${SEMVER} - docker tag ${MANIFESTIMAGE}:arm32v7-${META_TAG} ${MANIFESTIMAGE}:arm32v7-${SEMVER} - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${SEMVER} - docker push ${MANIFESTIMAGE}:amd64-${META_TAG} - docker push ${MANIFESTIMAGE}:arm32v7-${META_TAG} - docker push ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker push ${MANIFESTIMAGE}:amd64-latest - docker push ${MANIFESTIMAGE}:arm32v7-latest - docker push ${MANIFESTIMAGE}:arm64v8-latest - docker push ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} - docker push ${MANIFESTIMAGE}:arm32v7-${EXT_RELEASE_TAG} - docker push ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - docker push ${MANIFESTIMAGE}:amd64-${SEMVER} - docker push ${MANIFESTIMAGE}:arm32v7-${SEMVER} - docker push ${MANIFESTIMAGE}:arm64v8-${SEMVER} - docker manifest push --purge ${MANIFESTIMAGE}:latest || : - docker manifest create ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm32v7-latest ${MANIFESTIMAGE}:arm64v8-latest - docker manifest annotate ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:arm32v7-latest --os linux --arch arm - docker manifest annotate ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:arm64v8-latest --os linux --arch arm64 --variant v8 - docker manifest push --purge ${MANIFESTIMAGE}:${META_TAG} || : - docker manifest create ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm32v7-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker manifest annotate ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:arm32v7-${META_TAG} --os linux --arch arm - docker manifest annotate ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} --os linux --arch arm64 --variant v8 - docker manifest push --purge ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} || : - docker manifest create ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm32v7-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - docker manifest annotate ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm32v7-${EXT_RELEASE_TAG} --os linux --arch arm - docker manifest annotate ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} --os linux --arch arm64 --variant v8 - docker manifest push --purge ${MANIFESTIMAGE}:${SEMVER} || : - docker manifest create ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm32v7-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} - docker manifest annotate ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:arm32v7-${SEMVER} --os linux --arch arm - docker manifest annotate ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} --os linux --arch arm64 --variant v8 - docker manifest push --purge ${MANIFESTIMAGE}:latest - docker manifest push --purge ${MANIFESTIMAGE}:${META_TAG} - docker manifest push --purge ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} - docker manifest push --purge ${MANIFESTIMAGE}:${SEMVER} - done - ''' - } + retry_backoff(5,5) { sh '''#! /bin/bash - for DELETEIMAGE in "${GITHUBIMAGE}" "${GITLABIMAGE}" "${QUAYIMAGE}" "${IMAGE}"; do - docker rmi \ - ${DELETEIMAGE}:amd64-${META_TAG} \ - ${DELETEIMAGE}:amd64-latest \ - ${DELETEIMAGE}:amd64-${EXT_RELEASE_TAG} \ - ${DELETEIMAGE}:amd64-${SEMVER} \ - ${DELETEIMAGE}:arm32v7-${META_TAG} \ - ${DELETEIMAGE}:arm32v7-latest \ - ${DELETEIMAGE}:arm32v7-${EXT_RELEASE_TAG} \ - ${DELETEIMAGE}:arm32v7-${SEMVER} \ - ${DELETEIMAGE}:arm64v8-${META_TAG} \ - ${DELETEIMAGE}:arm64v8-latest \ - ${DELETEIMAGE}:arm64v8-${EXT_RELEASE_TAG} \ - ${DELETEIMAGE}:arm64v8-${SEMVER} || : + set -e + for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + [[ ${MANIFESTIMAGE%%/*} =~ \\. ]] && MANIFESTIMAGEPLUS="${MANIFESTIMAGE}" || MANIFESTIMAGEPLUS="docker.io/${MANIFESTIMAGE}" + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${MANIFESTIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then + CACHEIMAGE=${i} + fi + done + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + fi done - docker rmi \ - ghcr.io/linuxserver/lsiodev-buildcache:arm32v7-${COMMIT_SHA}-${BUILD_NUMBER} \ - ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || : - ''' + for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + fi + done + ''' } } } @@ -888,68 +1001,154 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - echo "Pushing New tag for current commit ${META_TAG}" - sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ - -d '{"tag":"'${META_TAG}'",\ - "object": "'${COMMIT_SHA}'",\ - "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\ - "type": "commit",\ - "tagger": {"name": "LinuxServer Jenkins","email": "jenkins@linuxserver.io","date": "'${GITHUB_DATE}'"}}' ''' - echo "Pushing New release for Tag" sh '''#! /bin/bash + echo "Auto-generating release notes" + if [ "$(git tag --points-at HEAD)" != "" ]; then + echo "Existing tag points to current commit, suggesting no new LS changes" + AUTO_RELEASE_NOTES="No changes" + else + AUTO_RELEASE_NOTES=$(curl -fsL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases/generate-notes \ + -d '{"tag_name":"'${META_TAG}'",\ + "target_commitish": "master"}' \ + | jq -r '.body' | sed 's|## What.s Changed||') + fi + echo "Pushing New tag for current commit ${META_TAG}" + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ + -d '{"tag":"'${META_TAG}'",\ + "object": "'${COMMIT_SHA}'",\ + "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\ + "type": "commit",\ + "tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' + echo "Pushing New release for Tag" echo "Updating to ${EXT_RELEASE_CLEAN}" > releasebody.json - echo '{"tag_name":"'${META_TAG}'",\ - "target_commitish": "master",\ - "name": "'${META_TAG}'",\ - "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**Remote Changes:**\\n\\n' > start - printf '","draft": false,"prerelease": false}' >> releasebody.json - paste -d'\\0' start releasebody.json > releasebody.json.done - curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done''' + jq -n \ + --arg tag_name "$META_TAG" \ + --arg target_commitish "master" \ + --arg ci_url "${CI_URL:-N/A}" \ + --arg ls_notes "$AUTO_RELEASE_NOTES" \ + --arg remote_notes "$(cat releasebody.json)" \ + '{ + "tag_name": $tag_name, + "target_commitish": $target_commitish, + "name": $tag_name, + "body": ("**CI Report:**\\n\\n" + $ci_url + "\\n\\n**LinuxServer Changes:**\\n\\n" + $ls_notes + "\\n\\n**Remote Changes:**\\n\\n" + $remote_notes), + "draft": false, + "prerelease": false }' > releasebody.json.done + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done + ''' } } - // Use helper container to sync the current README on master to the dockerhub endpoint - stage('Sync-README') { + // Add protection to the release branch + stage('Github-Release-Branch-Protection') { when { + branch "master" environment name: 'CHANGE_ID', value: '' environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: '3f9ba4d5-100d-45b0-a3c4-633fd6061207', - usernameVariable: 'DOCKERUSER', - passwordVariable: 'DOCKERPASS' - ] - ]) { - sh '''#! /bin/bash - set -e - TEMPDIR=$(mktemp -d) - docker pull ghcr.io/linuxserver/jenkins-builder:latest - docker run --rm -e CONTAINER_NAME=${CONTAINER_NAME} -e GITHUB_BRANCH="${BRANCH_NAME}" -v ${TEMPDIR}:/ansible/jenkins ghcr.io/linuxserver/jenkins-builder:latest - docker pull ghcr.io/linuxserver/readme-sync - docker run --rm=true \ - -e DOCKERHUB_USERNAME=$DOCKERUSER \ - -e DOCKERHUB_PASSWORD=$DOCKERPASS \ - -e GIT_REPOSITORY=${LS_USER}/${LS_REPO} \ - -e DOCKER_REPOSITORY=${IMAGE} \ - -e GIT_BRANCH=master \ - -v ${TEMPDIR}/docker-${CONTAINER_NAME}:/mnt \ - ghcr.io/linuxserver/readme-sync bash -c 'node sync' - rm -Rf ${TEMPDIR} ''' - } + echo "Setting up protection for release branch master" + sh '''#! /bin/bash + curl -H "Authorization: token ${GITHUB_TOKEN}" -X PUT https://api.github.com/repos/${LS_USER}/${LS_REPO}/branches/master/protection \ + -d $(jq -c . << EOF + { + "required_status_checks": null, + "enforce_admins": false, + "required_pull_request_reviews": { + "dismiss_stale_reviews": false, + "require_code_owner_reviews": false, + "require_last_push_approval": false, + "required_approving_review_count": 1 + }, + "restrictions": null, + "required_linear_history": false, + "allow_force_pushes": false, + "allow_deletions": false, + "block_creations": false, + "required_conversation_resolution": true, + "lock_branch": false, + "allow_fork_syncing": false, + "required_signatures": false + } +EOF + ) ''' } } // If this is a Pull request send the CI link as a comment on it stage('Pull Request Comment') { when { not {environment name: 'CHANGE_ID', value: ''} - environment name: 'CI', value: 'true' environment name: 'EXIT_STATUS', value: '' } steps { - sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/issues/${PULL_REQUEST}/comments \ - -d '{"body": "I am a bot, here are the test results for this PR: \\n'${CI_URL}' \\n'${SHELLCHECK_URL}'"}' ''' + sh '''#! /bin/bash + # Function to retrieve JSON data from URL + get_json() { + local url="$1" + local response=$(curl -s "$url") + if [ $? -ne 0 ]; then + echo "Failed to retrieve JSON data from $url" + return 1 + fi + local json=$(echo "$response" | jq .) + if [ $? -ne 0 ]; then + echo "Failed to parse JSON data from $url" + return 1 + fi + echo "$json" + } + + build_table() { + local data="$1" + + # Get the keys in the JSON data + local keys=$(echo "$data" | jq -r 'to_entries | map(.key) | .[]') + + # Check if keys are empty + if [ -z "$keys" ]; then + echo "JSON report data does not contain any keys or the report does not exist." + return 1 + fi + + # Build table header + local header="| Tag | Passed |\\n| --- | --- |\\n" + + # Loop through the JSON data to build the table rows + local rows="" + for build in $keys; do + local status=$(echo "$data" | jq -r ".[\\"$build\\"].test_success") + if [ "$status" = "true" ]; then + status="✅" + else + status="❌" + fi + local row="| "$build" | "$status" |\\n" + rows="${rows}${row}" + done + + local table="${header}${rows}" + local escaped_table=$(echo "$table" | sed 's/\"/\\\\"/g') + echo "$escaped_table" + } + + if [[ "${CI}" = "true" ]]; then + # Retrieve JSON data from URL + data=$(get_json "$CI_JSON_URL") + # Create table from JSON data + table=$(build_table "$data") + echo -e "$table" + + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, here are the test results for this PR: \\n${CI_URL}\\n${SHELLCHECK_URL}\\n${table}\\"}" + else + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, here is the pushed image/manifest for this PR: \\n\\n\\`${GITHUBIMAGE}:${META_TAG}\\`\\"}" + fi + ''' + } } } @@ -958,24 +1157,94 @@ pipeline { ###################### */ post { always { + sh '''#!/bin/bash + rm -rf /config/.ssh/id_sign + rm -rf /config/.ssh/id_sign.pub + git config --global --unset gpg.format + git config --global --unset user.signingkey + git config --global --unset commit.gpgsign + ''' script{ + env.JOB_DATE = sh( + script: '''date '+%Y-%m-%dT%H:%M:%S%:z' ''', + returnStdout: true).trim() if (env.EXIT_STATUS == "ABORTED"){ sh 'echo "build aborted"' - } - else if (currentBuild.currentResult == "SUCCESS"){ - sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://wiki.jenkins-ci.org/download/attachments/2916393/headshot.png","embeds": [{"color": 1681177,\ - "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** Success\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ - "username": "Jenkins"}' ${BUILDS_DISCORD} ''' - } - else { - sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://wiki.jenkins-ci.org/download/attachments/2916393/headshot.png","embeds": [{"color": 16711680,\ - "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** failure\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ + }else{ + if (currentBuild.currentResult == "SUCCESS"){ + if (env.GITHUBIMAGE =~ /lspipepr/){ + env.JOB_WEBHOOK_STATUS='Success' + env.JOB_WEBHOOK_COLOUR=3957028 + env.JOB_WEBHOOK_FOOTER='PR Build' + }else if (env.GITHUBIMAGE =~ /lsiodev/){ + env.JOB_WEBHOOK_STATUS='Success' + env.JOB_WEBHOOK_COLOUR=3957028 + env.JOB_WEBHOOK_FOOTER='Dev Build' + }else{ + env.JOB_WEBHOOK_STATUS='Success' + env.JOB_WEBHOOK_COLOUR=1681177 + env.JOB_WEBHOOK_FOOTER='Live Build' + } + }else{ + if (env.GITHUBIMAGE =~ /lspipepr/){ + env.JOB_WEBHOOK_STATUS='Failure' + env.JOB_WEBHOOK_COLOUR=12669523 + env.JOB_WEBHOOK_FOOTER='PR Build' + }else if (env.GITHUBIMAGE =~ /lsiodev/){ + env.JOB_WEBHOOK_STATUS='Failure' + env.JOB_WEBHOOK_COLOUR=12669523 + env.JOB_WEBHOOK_FOOTER='Dev Build' + }else{ + env.JOB_WEBHOOK_STATUS='Failure' + env.JOB_WEBHOOK_COLOUR=16711680 + env.JOB_WEBHOOK_FOOTER='Live Build' + } + } + sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"'color'": '${JOB_WEBHOOK_COLOUR}',\ + "footer": {"text" : "'"${JOB_WEBHOOK_FOOTER}"'"},\ + "timestamp": "'${JOB_DATE}'",\ + "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** '${JOB_WEBHOOK_STATUS}'\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ "username": "Jenkins"}' ${BUILDS_DISCORD} ''' } } } cleanup { + sh '''#! /bin/bash + echo "Pruning builder!!" + docker builder prune -f --builder container || : + containers=$(docker ps -q) + if [[ -n "${containers}" ]]; then + BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') + for container in ${containers}; do + if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then + echo "skipping buildx container in docker stop" + else + echo "Stopping container ${container}" + docker stop ${container} + fi + done + fi + docker system prune -f --volumes || : + docker image prune -af || : + ''' cleanWs() } } } + +def retry_backoff(int max_attempts, int power_base, Closure c) { + int n = 0 + while (n < max_attempts) { + try { + c() + return + } catch (err) { + if ((n + 1) >= max_attempts) { + throw err + } + sleep(power_base ** n) + n++ + } + } + return +} diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md index 5ab8b72c..45e2782c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ -<!-- DO NOT EDIT THIS FILE MANUALLY --> -<!-- Please read the https://github.com/linuxserver/docker-code-server/blob/master/.github/CONTRIBUTING.md --> - +<!-- DO NOT EDIT THIS FILE MANUALLY --> +<!-- Please read https://github.com/linuxserver/docker-code-server/blob/master/.github/CONTRIBUTING.md --> [![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)](https://linuxserver.io) [![Blog](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Blog)](https://blog.linuxserver.io "all the things you can do with our containers including How-To guides, opinions and much more!") -[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://discord.gg/YWrKVTn "realtime support / chat with the community and the team.") +[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://linuxserver.io/discord "realtime support / chat with the community and the team.") [![Discourse](https://img.shields.io/discourse/https/discourse.linuxserver.io/topics.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=discourse)](https://discourse.linuxserver.io "post on our community forum.") -[![Fleet](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Fleet)](https://fleet.linuxserver.io "an online web interface which displays all of our maintained images.") [![GitHub](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=GitHub&logo=github)](https://github.com/linuxserver "view the source for all of our repositories.") [![Open Collective](https://img.shields.io/opencollective/all/linuxserver.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Supporters&logo=open%20collective)](https://opencollective.com/linuxserver "please consider helping us by either donating or contributing to our budget") @@ -21,14 +19,14 @@ The [LinuxServer.io](https://linuxserver.io) team brings you another container r Find us at: * [Blog](https://blog.linuxserver.io) - all the things you can do with our containers including How-To guides, opinions and much more! -* [Discord](https://discord.gg/YWrKVTn) - realtime support / chat with the community and the team. +* [Discord](https://linuxserver.io/discord) - realtime support / chat with the community and the team. * [Discourse](https://discourse.linuxserver.io) - post on our community forum. -* [Fleet](https://fleet.linuxserver.io) - an online web interface which displays all of our maintained images. * [GitHub](https://github.com/linuxserver) - view the source for all of our repositories. * [Open Collective](https://opencollective.com/linuxserver) - please consider helping us by either donating or contributing to our budget # [linuxserver/code-server](https://github.com/linuxserver/docker-code-server) +[![Scarf.io pulls](https://scarf.sh/installs-badge/linuxserver-ci/linuxserver%2Fcode-server?color=94398d&label-color=555555&logo-color=ffffff&style=for-the-badge&package-type=docker)](https://scarf.sh) [![GitHub Stars](https://img.shields.io/github/stars/linuxserver/docker-code-server.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=github)](https://github.com/linuxserver/docker-code-server) [![GitHub Release](https://img.shields.io/github/release/linuxserver/docker-code-server.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=github)](https://github.com/linuxserver/docker-code-server/releases) [![GitHub Package Repository](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=GitHub%20Package&logo=github)](https://github.com/linuxserver/docker-code-server/packages) @@ -51,27 +49,16 @@ Find us at: ## Supported Architectures -Our images support multiple architectures such as `x86-64`, `arm64` and `armhf`. We utilise the docker manifest for multi-platform awareness. More information is available from docker [here](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md#manifest-list) and our announcement [here](https://blog.linuxserver.io/2019/02/21/the-lsio-pipeline-project/). +We utilise the docker manifest for multi-platform awareness. More information is available from docker [here](https://distribution.github.io/distribution/spec/manifest-v2-2/#manifest-list) and our announcement [here](https://blog.linuxserver.io/2019/02/21/the-lsio-pipeline-project/). -Simply pulling `lscr.io/linuxserver/code-server` should retrieve the correct image for your arch, but you can also pull specific arch images via tags. +Simply pulling `lscr.io/linuxserver/code-server:latest` should retrieve the correct image for your arch, but you can also pull specific arch images via tags. The architectures supported by this image are: -| Architecture | Tag | -| :----: | --- | -| x86-64 | amd64-latest | -| arm64 | arm64v8-latest | -| armhf | arm32v7-latest | - -## Version Tags - -This image provides various versions that are available via tags. `latest` tag usually provides the latest stable version. Others are considered under development and caution must be exercised when using them. - -| Tag | Description | -| :----: | --- | -| latest | Stable releases | -| focal | Stable releases, based on Ubuntu Focal | -| development | DEPRECATED (no longer updated) - Prereleases from their GitHub | +| Architecture | Available | Tag | +| :----: | :----: | ---- | +| x86-64 | ✅ | amd64-\<version tag\> | +| arm64 | ✅ | arm64v8-\<version tag\> | ## Application Setup @@ -88,30 +75,51 @@ git config --global user.email "email address" How to create the [hashed password](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#can-i-store-my-password-hashed). +## Read-Only Operation + +This image can be run with a read-only container filesystem. For details please [read the docs](https://docs.linuxserver.io/misc/read-only/). + +### Caveats + +* `/tmp` must be mounted to tmpfs +* `sudo` will not be available + +## Non-Root Operation + +This image can be run with a non-root user. For details please [read the docs](https://docs.linuxserver.io/misc/non-root/). + +### Caveats + +* `sudo` will not be available + ## Usage -Here are some example snippets to help you get started creating a container. +To help you get started creating a container from this image you can either use docker-compose or the docker cli. + +>[!NOTE] +>Unless a parameter is flagged as 'optional', it is *mandatory* and a value must be provided. ### docker-compose (recommended, [click here for more info](https://docs.linuxserver.io/general/docker-compose)) ```yaml --- -version: "2.1" services: code-server: - image: lscr.io/linuxserver/code-server + image: lscr.io/linuxserver/code-server:latest container_name: code-server environment: - PUID=1000 - PGID=1000 - - TZ=Europe/London + - TZ=Etc/UTC - PASSWORD=password #optional - HASHED_PASSWORD= #optional - SUDO_PASSWORD=password #optional - SUDO_PASSWORD_HASH= #optional - PROXY_DOMAIN=code-server.my.domain #optional + - DEFAULT_WORKSPACE=/config/workspace #optional + - PWA_APPNAME=code-server #optional volumes: - - /path/to/appdata/config:/config + - /path/to/code-server/config:/config ports: - 8443:8443 restart: unless-stopped @@ -124,34 +132,40 @@ docker run -d \ --name=code-server \ -e PUID=1000 \ -e PGID=1000 \ - -e TZ=Europe/London \ + -e TZ=Etc/UTC \ -e PASSWORD=password `#optional` \ -e HASHED_PASSWORD= `#optional` \ -e SUDO_PASSWORD=password `#optional` \ -e SUDO_PASSWORD_HASH= `#optional` \ -e PROXY_DOMAIN=code-server.my.domain `#optional` \ + -e DEFAULT_WORKSPACE=/config/workspace `#optional` \ + -e PWA_APPNAME=code-server `#optional` \ -p 8443:8443 \ - -v /path/to/appdata/config:/config \ + -v /path/to/code-server/config:/config \ --restart unless-stopped \ - lscr.io/linuxserver/code-server + lscr.io/linuxserver/code-server:latest ``` ## Parameters -Container images are configured using parameters passed at runtime (such as those above). These parameters are separated by a colon and indicate `<external>:<internal>` respectively. For example, `-p 8080:80` would expose port `80` from inside the container to be accessible from the host's IP on port `8080` outside the container. +Containers are configured using parameters passed at runtime (such as those above). These parameters are separated by a colon and indicate `<external>:<internal>` respectively. For example, `-p 8080:80` would expose port `80` from inside the container to be accessible from the host's IP on port `8080` outside the container. | Parameter | Function | | :----: | --- | -| `-p 8443` | web gui | +| `-p 8443:8443` | web gui | | `-e PUID=1000` | for UserID - see below for explanation | | `-e PGID=1000` | for GroupID - see below for explanation | -| `-e TZ=Europe/London` | Specify a timezone to use EG Europe/London | +| `-e TZ=Etc/UTC` | specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). | | `-e PASSWORD=password` | Optional web gui password, if `PASSWORD` or `HASHED_PASSWORD` is not provided, there will be no auth. | | `-e HASHED_PASSWORD=` | Optional web gui password, overrides `PASSWORD`, instructions on how to create it is below. | | `-e SUDO_PASSWORD=password` | If this optional variable is set, user will have sudo access in the code-server terminal with the specified password. | | `-e SUDO_PASSWORD_HASH=` | Optionally set sudo password via hash (takes priority over `SUDO_PASSWORD` var). Format is `$type$salt$hashed`. | -| `-e PROXY_DOMAIN=code-server.my.domain` | If this optional variable is set, this domain will be proxied for subdomain proxying. See [Documentation](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#sub-domains) | +| `-e PROXY_DOMAIN=code-server.my.domain` | If this optional variable is set, this domain will be proxied for subdomain proxying. See [Documentation](https://github.com/coder/code-server/blob/main/docs/guide.md#using-a-subdomain) | +| `-e DEFAULT_WORKSPACE=/config/workspace` | If this optional variable is set, code-server will open this directory by default | +| `-e PWA_APPNAME=code-server` | If this optional variable is set, the PWA app will the specified name. | | `-v /config` | Contains all relevant configuration files. | +| `--read-only=true` | Run container with a read-only filesystem. Please [read the docs](https://docs.linuxserver.io/misc/read-only/). | +| `--user=1000:1000` | Run container with a non-root user. Please [read the docs](https://docs.linuxserver.io/misc/non-root/). | ## Environment variables from files (Docker secrets) @@ -160,10 +174,10 @@ You can set any environment variable from a file by using a special prepend `FIL As an example: ```bash --e FILE__PASSWORD=/run/secrets/mysecretpassword +-e FILE__MYVAR=/run/secrets/mysecretvariable ``` -Will set the environment variable `PASSWORD` based on the contents of the `/run/secrets/mysecretpassword` file. +Will set the environment variable `MYVAR` based on the contents of the `/run/secrets/mysecretvariable` file. ## Umask for running applications @@ -172,15 +186,20 @@ Keep in mind umask is not chmod it subtracts from permissions based on it's valu ## User / Group Identifiers -When using volumes (`-v` flags) permissions issues can arise between the host OS and the container, we avoid this issue by allowing you to specify the user `PUID` and group `PGID`. +When using volumes (`-v` flags), permissions issues can arise between the host OS and the container, we avoid this issue by allowing you to specify the user `PUID` and group `PGID`. Ensure any volume directories on the host are owned by the same user you specify and any permissions issues will vanish like magic. -In this instance `PUID=1000` and `PGID=1000`, to find yours use `id user` as below: +In this instance `PUID=1000` and `PGID=1000`, to find yours use `id your_user` as below: ```bash - $ id username - uid=1000(dockeruser) gid=1000(dockergroup) groups=1000(dockergroup) +id your_user +``` + +Example output: + +```text +uid=1000(your_user) gid=1000(your_user) groups=1000(your_user) ``` ## Docker Mods @@ -191,53 +210,101 @@ We publish various [Docker Mods](https://github.com/linuxserver/docker-mods) to ## Support Info -* Shell access whilst the container is running: `docker exec -it code-server /bin/bash` -* To monitor the logs of the container in realtime: `docker logs -f code-server` -* container version number - * `docker inspect -f '{{ index .Config.Labels "build_version" }}' code-server` -* image version number - * `docker inspect -f '{{ index .Config.Labels "build_version" }}' lscr.io/linuxserver/code-server` +* Shell access whilst the container is running: + + ```bash + docker exec -it code-server /bin/bash + ``` + +* To monitor the logs of the container in realtime: + + ```bash + docker logs -f code-server + ``` + +* Container version number: + + ```bash + docker inspect -f '{{ index .Config.Labels "build_version" }}' code-server + ``` + +* Image version number: + + ```bash + docker inspect -f '{{ index .Config.Labels "build_version" }}' lscr.io/linuxserver/code-server:latest + ``` ## Updating Info -Most of our images are static, versioned, and require an image update and container recreation to update the app inside. With some exceptions (ie. nextcloud, plex), we do not recommend or support updating apps inside the container. Please consult the [Application Setup](#application-setup) section above to see if it is recommended for the image. +Most of our images are static, versioned, and require an image update and container recreation to update the app inside. With some exceptions (noted in the relevant readme.md), we do not recommend or support updating apps inside the container. Please consult the [Application Setup](#application-setup) section above to see if it is recommended for the image. Below are the instructions for updating containers: ### Via Docker Compose -* Update all images: `docker-compose pull` - * or update a single image: `docker-compose pull code-server` -* Let compose update all containers as necessary: `docker-compose up -d` - * or update a single container: `docker-compose up -d code-server` -* You can also remove the old dangling images: `docker image prune` +* Update images: + * All images: + + ```bash + docker-compose pull + ``` + + * Single image: + + ```bash + docker-compose pull code-server + ``` + +* Update containers: + * All containers: + + ```bash + docker-compose up -d + ``` + + * Single container: + + ```bash + docker-compose up -d code-server + ``` + +* You can also remove the old dangling images: + + ```bash + docker image prune + ``` ### Via Docker Run -* Update the image: `docker pull lscr.io/linuxserver/code-server` -* Stop the running container: `docker stop code-server` -* Delete the container: `docker rm code-server` -* Recreate a new container with the same docker run parameters as instructed above (if mapped correctly to a host folder, your `/config` folder and settings will be preserved) -* You can also remove the old dangling images: `docker image prune` +* Update the image: + + ```bash + docker pull lscr.io/linuxserver/code-server:latest + ``` -### Via Watchtower auto-updater (only use if you don't remember the original parameters) +* Stop the running container: -* Pull the latest image at its tag and replace it with the same env variables in one run: + ```bash + docker stop code-server + ``` - ```bash - docker run --rm \ - -v /var/run/docker.sock:/var/run/docker.sock \ - containrrr/watchtower \ - --run-once code-server - ``` +* Delete the container: -* You can also remove the old dangling images: `docker image prune` + ```bash + docker rm code-server + ``` + +* Recreate a new container with the same docker run parameters as instructed above (if mapped correctly to a host folder, your `/config` folder and settings will be preserved) +* You can also remove the old dangling images: -**Note:** We do not endorse the use of Watchtower as a solution to automated updates of existing Docker containers. In fact we generally discourage automated updates. However, this is a useful tool for one-time manual updates of containers where you have forgotten the original parameters. In the long term, we highly recommend using [Docker Compose](https://docs.linuxserver.io/general/docker-compose). + ```bash + docker image prune + ``` ### Image Update Notifications - Diun (Docker Image Update Notifier) -* We recommend [Diun](https://crazymax.dev/diun/) for update notifications. Other tools that automatically update containers unattended are not recommended or supported. +>[!TIP] +>We recommend [Diun](https://crazymax.dev/diun/) for update notifications. Other tools that automatically update containers unattended are not recommended or supported. ## Building locally @@ -252,16 +319,28 @@ docker build \ -t lscr.io/linuxserver/code-server:latest . ``` -The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static` +The ARM variants can be built on x86_64 hardware and vice versa using `lscr.io/linuxserver/qemu-static` ```bash -docker run --rm --privileged multiarch/qemu-user-static:register --reset +docker run --rm --privileged lscr.io/linuxserver/qemu-static --reset ``` Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. ## Versions +* **10.08.25:** - Let server listen on both ipv4 and ipv6. +* **03.06.25:** - Allow setting PWA name using env var `PWA_APPNAME`. +* **13.10.24:** - Only chown config folder when change to ownership or new install is detected. +* **09.10.24:** - Manage permissions in /config/.ssh according to file type +* **19.08.24:** - Rebase to Ubuntu Noble. +* **01.07.23:** - Deprecate armhf. As announced [here](https://www.linuxserver.io/blog/a-farewell-to-arm-hf) +* **05.10.22:** - Install recommended deps to maintain parity with the older images. +* **29.09.22:** - Rebase to jammy, switch to s6v3. Fix chown logic to skip `/config/workspace` contents. +* **20.02.22:** - Install using the official tarballs. +* **29.12.21:** - Add `install-extension` as a helper for mods to install extensions. +* **06.12.21:** - Add `DEFAULT_WORKSPACE` env var. +* **29.11.21:** - Rebase to Ubuntu focal. * **16.09.21:** - Fix slow `chown` on large workspace (contents of workspace folder no longer chowned). * **11.07.21:** - Bump node to 14 to fix builds * **08.05.21:** - Fix doc link diff --git a/jenkins-vars.yml b/jenkins-vars.yml index f05393fc..d9a9058b 100644 --- a/jenkins-vars.yml +++ b/jenkins-vars.yml @@ -3,7 +3,7 @@ # jenkins variables project_name: docker-code-server external_type: na -custom_version_command: "curl -sX GET https://registry.yarnpkg.com/code-server | jq -r '.\"dist-tags\".latest' | sed 's|^|v|'" +custom_version_command: "curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest | jq -r '.tag_name' | sed 's|^v||'" release_type: stable release_tag: latest ls_branch: master @@ -22,6 +22,6 @@ repo_vars: - CI_PORT='8443' - CI_SSL='false' - CI_DELAY='120' - - CI_DOCKERENV='TZ=US/Pacific' - - CI_AUTH='user:password' + - CI_DOCKERENV='' + - CI_AUTH='' - CI_WEBPATH='' diff --git a/package_versions.txt b/package_versions.txt index 82529696..40f51d7d 100755 --- a/package_versions.txt +++ b/package_versions.txt @@ -1,185 +1,527 @@ -adduser3.116ubuntu1 -apt1.6.14 -apt-utils1.6.14 -base-files10.1ubuntu2.11 -base-passwd3.5.44 -bash4.4.18-2ubuntu1.2 -bsdutils1:2.31.1-0.4ubuntu3.7 -bzip21.0.6-8.1ubuntu0.2 -ca-certificates20210119~18.04.2 -coreutils8.28-1ubuntu1 -curl7.58.0-2ubuntu3.16 -dash0.5.8-2.10 -debconf1.5.66ubuntu1 -debianutils4.8.4 -diffutils1:3.6-1 -dirmngr2.2.4-1ubuntu1.4 -dpkg1.19.0.5ubuntu2.3 -e2fsprogs1.44.1-1ubuntu1.3 -fdisk2.31.1-0.4ubuntu3.7 -file1:5.32-2ubuntu0.4 -findutils4.6.0+git+20170828-2 -gcc-8-base8.4.0-1ubuntu1~18.04 -git1:2.17.1-1ubuntu0.9 -git-man1:2.17.1-1ubuntu0.9 -gnupg2.2.4-1ubuntu1.4 -gnupg-l10n2.2.4-1ubuntu1.4 -gnupg-utils2.2.4-1ubuntu1.4 -gpg2.2.4-1ubuntu1.4 -gpg-agent2.2.4-1ubuntu1.4 -gpgconf2.2.4-1ubuntu1.4 -gpgsm2.2.4-1ubuntu1.4 -gpgv2.2.4-1ubuntu1.4 -gpg-wks-client2.2.4-1ubuntu1.4 -gpg-wks-server2.2.4-1ubuntu1.4 -grep3.1-2build1 -gzip1.6-5ubuntu1.1 -hostname3.20 -init-system-helpers1.51 -jq1.5+dfsg-2 -krb5-locales1.16-2ubuntu0.2 -less487-0.1 -libacl12.2.52-3build1 -libapt-inst2.01.6.14 -libapt-pkg5.01.6.14 -libasn1-8-heimdal7.5.0+dfsg-1 -libassuan02.5.1-2 -libattr11:2.4.47-2build1 -libaudit11:2.8.2-1ubuntu1.1 -libaudit-common1:2.8.2-1ubuntu1.1 -libblkid12.31.1-0.4ubuntu3.7 -libbsd00.8.7-1ubuntu0.1 -libbz2-1.01.0.6-8.1ubuntu0.2 -libc62.27-3ubuntu1.4 -libcap-ng00.7.7-3.1 -libc-bin2.27-3ubuntu1.4 -libcom-err21.44.1-1ubuntu1.3 -libcurl3-gnutls7.58.0-2ubuntu3.16 -libcurl47.58.0-2ubuntu3.16 -libdb5.35.3.28-13.1ubuntu1.1 -libdebconfclient00.213ubuntu1 -libedit23.1-20170329-1 -liberror-perl0.17025-1 -libexpat12.2.5-3ubuntu0.2 -libext2fs21.44.1-1ubuntu1.3 -libfdisk12.31.1-0.4ubuntu3.7 -libffi63.2.1-8 -libgcc11:8.4.0-1ubuntu1~18.04 -libgcrypt201.8.1-4ubuntu1.3 -libgdbm51.14.1-6 -libgdbm-compat41.14.1-6 -libgmp102:6.1.2+dfsg-2 -libgnutls303.5.18-1ubuntu1.5 -libgpg-error01.27-6 -libgssapi3-heimdal7.5.0+dfsg-1 -libgssapi-krb5-21.16-2ubuntu0.2 -libhcrypto4-heimdal7.5.0+dfsg-1 -libheimbase1-heimdal7.5.0+dfsg-1 -libheimntlm0-heimdal7.5.0+dfsg-1 -libhogweed43.4.1-0ubuntu0.18.04.1 -libhx509-5-heimdal7.5.0+dfsg-1 -libidn2-02.0.4-1.1ubuntu0.2 -libjq11.5+dfsg-2 -libk5crypto31.16-2ubuntu0.2 -libkeyutils11.5.9-9.2ubuntu2 -libkrb5-26-heimdal7.5.0+dfsg-1 -libkrb5-31.16-2ubuntu0.2 -libkrb5support01.16-2ubuntu0.2 -libksba81.3.5-2 -libldap-2.4-22.4.45+dfsg-1ubuntu1.10 -libldap-common2.4.45+dfsg-1ubuntu1.10 -liblz4-10.0~r131-2ubuntu3.1 -liblzma55.2.2-1.3 -libmagic11:5.32-2ubuntu0.4 -libmagic-mgc1:5.32-2ubuntu0.4 -libmount12.31.1-0.4ubuntu3.7 -libncurses56.1-1ubuntu1.18.04 -libncursesw56.1-1ubuntu1.18.04 -libnettle63.4.1-0ubuntu0.18.04.1 -libnghttp2-141.30.0-1ubuntu1 -libnpth01.5-3 -libonig46.7.0-1 -libp11-kit00.23.9-2ubuntu0.1 -libpam0g1.1.8-3.6ubuntu2.18.04.3 -libpam-modules1.1.8-3.6ubuntu2.18.04.3 -libpam-modules-bin1.1.8-3.6ubuntu2.18.04.3 -libpam-runtime1.1.8-3.6ubuntu2.18.04.3 -libpcre32:8.39-9 -libperl5.265.26.1-6ubuntu0.5 -libprocps62:3.3.12-3ubuntu1.2 -libpsl50.19.1-5build1 -libpython2.7-minimal2.7.17-1~18.04ubuntu1.6 -libpython2.7-stdlib2.7.17-1~18.04ubuntu1.6 -libpython-stdlib2.7.15~rc1-1 -libreadline77.0-3 -libroken18-heimdal7.5.0+dfsg-1 -librtmp12.4+20151223.gitfa8646d.1-1 -libsasl2-22.1.27~101-g0780600+dfsg-3ubuntu2.3 -libsasl2-modules2.1.27~101-g0780600+dfsg-3ubuntu2.3 -libsasl2-modules-db2.1.27~101-g0780600+dfsg-3ubuntu2.3 -libseccomp22.5.1-1ubuntu1~18.04.1 -libselinux12.7-2build2 -libsemanage12.7-2build2 -libsemanage-common2.7-2build2 -libsepol12.7-1 -libsmartcols12.31.1-0.4ubuntu3.7 -libsqlite3-03.22.0-1ubuntu0.4 -libss21.44.1-1ubuntu1.3 -libssl1.0.01.0.2n-1ubuntu5.7 -libssl1.11.1.1-1ubuntu2.1~18.04.13 -libstdc++68.4.0-1ubuntu1~18.04 -libsystemd0237-3ubuntu10.52 -libtasn1-64.13-2 -libtinfo56.1-1ubuntu1.18.04 -libudev1237-3ubuntu10.52 -libunistring20.9.9-0ubuntu2 -libuuid12.31.1-0.4ubuntu3.7 -libwind0-heimdal7.5.0+dfsg-1 -libx11-62:1.6.4-3ubuntu0.4 -libx11-data2:1.6.4-3ubuntu0.4 -libxau61:1.0.8-1ubuntu1 -libxcb11.13-2~ubuntu18.04 -libxdmcp61:1.1.2-3 -libxext62:1.3.3-1 -libxmuu12:1.1.2-2 -libzstd11.3.3+dfsg-2ubuntu1.2 -locales2.27-3ubuntu1.4 -login1:4.5-1ubuntu2 -lsb-base9.20170808ubuntu1 -mawk1.3.3-17ubuntu3 -mime-support3.60ubuntu1 -mount2.31.1-0.4ubuntu3.7 -multiarch-support2.27-3ubuntu1.4 -nano2.9.3-2 -ncurses-base6.1-1ubuntu1.18.04 -ncurses-bin6.1-1ubuntu1.18.04 -netbase5.4 -net-tools1.60+git20161116.90da8a0-1ubuntu1 -nodejs14.18.1-1nodesource1 -openssh-client1:7.6p1-4ubuntu0.5 -openssl1.1.1-1ubuntu2.1~18.04.13 -passwd1:4.5-1ubuntu2 -patch2.7.6-2ubuntu1.1 -perl5.26.1-6ubuntu0.5 -perl-base5.26.1-6ubuntu0.5 -perl-modules-5.265.26.1-6ubuntu0.5 -pinentry-curses1.1.0-1 -procps2:3.3.12-3ubuntu1.2 -publicsuffix20180223.1310-1 -python2.7.15~rc1-1 -python2.72.7.17-1~18.04ubuntu1.6 -python2.7-minimal2.7.17-1~18.04ubuntu1.6 -python-minimal2.7.15~rc1-1 -readline-common7.0-3 -sed4.4-2 -sensible-utils0.0.12 -sudo1.8.21p2-3ubuntu1.4 -sysvinit-utils2.88dsf-59.10ubuntu1 -tar1.29b-2ubuntu0.2 -tzdata2021a-2ubuntu0.18.04 -ubuntu-keyring2018.09.18.1~18.04.2 -util-linux2.31.1-0.4ubuntu3.7 -xauth1:1.0.10-1 -xz-utils5.2.2-1.3 -yarn1.22.15-1 -zlib1g1:1.2.11.dfsg-0ubuntu2 +NAME VERSION TYPE +@anthropic-ai/sandbox-runtime 0.0.23 npm +@babel/runtime 7.27.6 npm +@coder/logger 3.0.1 npm +@epic-web/invariant 1.0.0 npm +@microsoft/1ds-core-js 3.2.13 npm +@microsoft/1ds-post-js 3.2.13 npm +@microsoft/applicationinsights-core-js 2.8.15 npm +@microsoft/applicationinsights-shims 2.0.2 npm +@microsoft/dynamicproto-js 1.1.9 npm +@parcel/watcher 2.5.6 npm +@parcel/watcher-linux-x64-glibc 2.5.6 npm +@parcel/watcher-linux-x64-musl 2.5.6 npm +@phc/format 1.0.0 npm +@pondwader/socks5-server 1.0.10 npm +@tootallnate/once 3.0.0 npm +@tootallnate/quickjs-emscripten 0.23.0 npm +@types/lodash 4.17.23 npm +@types/lodash-es 4.17.12 npm +@vscode/deviceid 0.1.4 npm +@vscode/iconv-lite-umd 0.7.1 npm +@vscode/native-watchdog 1.4.6 npm +@vscode/proxy-agent 0.37.0 npm +@vscode/ripgrep 1.15.14 npm +@vscode/spdlog 0.15.7 npm +@vscode/tree-sitter-wasm 0.3.0 npm +@vscode/vscode-languagedetection 1.0.21 npm +@vscode/windows-process-tree 0.6.3 npm +@vscode/windows-registry 1.1.3 npm +@xterm/addon-clipboard 0.3.0-beta.109 npm +@xterm/addon-image 0.10.0-beta.109 npm +@xterm/addon-ligatures 0.11.0-beta.109 npm +@xterm/addon-progress 0.3.0-beta.109 npm +@xterm/addon-search 0.17.0-beta.109 npm +@xterm/addon-serialize 0.15.0-beta.109 npm +@xterm/addon-unicode11 0.10.0-beta.109 npm +@xterm/addon-webgl 0.20.0-beta.108 npm +@xterm/headless 6.1.0-beta.109 npm +@xterm/xterm 6.1.0-beta.109 npm +ConPTY Interface Library 1.23.251008001 binary (+1 duplicate) +Console Window and PTY Host (Open Source) 1.23.251008001 binary (+1 duplicate) +accepts 2.0.0 npm +adduser 3.137ubuntu1 deb +agent-base 7.1.1 npm +agent-base 7.1.3 npm (+3 duplicates) +apt 2.8.3 deb +apt-utils 2.8.3 deb +argon2 0.44.0 npm +argparse 2.0.1 npm +ast-types 0.13.4 npm +base-files 13ubuntu10.4 deb +base-passwd 3.6.3build1 deb +base64-js 1.5.1 npm +bash 5.2.21-2ubuntu4 deb +basic-ftp 5.0.5 npm +bat 1.0.0 npm +beep-boop 1.2.3 npm +bindings 1.5.0 npm +bl 4.1.0 npm +body-parser 2.2.2 npm +bsdutils 1:2.39.3-9ubuntu6.4 deb +buffer 5.7.1 npm +buffer-alloc 1.2.0 npm +buffer-alloc-unsafe 1.1.0 npm +buffer-crc32 0.2.13 npm +buffer-fill 1.0.0 npm +builtin-notebook-renderers 1.0.0 npm +bytes 3.1.2 npm +ca-certificates 20240203 deb +call-bind-apply-helpers 1.0.2 npm +call-bound 1.0.4 npm +catatonit 0.1.7-1 deb +charenc 0.0.2 npm +chownr 1.1.4 npm +clojure 1.0.0 npm +code-server 1.109.5 npm +code-server 4.109.5 npm +coffeescript 1.0.0 npm +commander 12.1.0 npm +commander 8.3.0 npm +compressible 2.0.18 npm +compression 1.8.1 npm +configuration-editing 1.0.0 npm +content-disposition 1.0.0 npm +content-type 1.0.5 npm +cookie 0.7.2 npm (+1 duplicate) +cookie-parser 1.4.7 npm +cookie-signature 1.0.6 npm +cookie-signature 1.2.2 npm +coreutils 9.4-3ubuntu6.1 deb +cpp 1.0.0 npm +cron 3.0pl1-184ubuntu2 deb +cron-daemon-common 3.0pl1-184ubuntu2 deb +cross-env 10.1.0 npm +cross-spawn 7.0.6 npm +crypt 0.0.2 npm +csharp 1.0.0 npm +css 1.0.0 npm +css-language-features 1.0.0 npm +curl 8.5.0-2ubuntu10.7 deb +dart 1.0.0 npm +dash 0.5.12-6ubuntu5 deb +data-uri-to-buffer 6.0.2 npm +debconf 1.5.86ubuntu1 deb +debianutils 5.17build1 deb +debug 2.6.9 npm +debug 4.3.4 npm +debug 4.4.3 npm +debug-auto-launch 1.0.0 npm +debug-server-ready 1.0.0 npm +decompress-response 6.0.0 npm +deep-extend 0.6.0 npm +degenerator 5.0.1 npm +depd 2.0.0 npm +detect-libc 2.0.4 npm +diff 1.0.0 npm +diffutils 1:3.10-1build1 deb +dirmngr 2.4.4-2ubuntu17.4 deb +docker 1.0.0 npm +dotenv 1.0.0 npm +dpkg 1.22.6ubuntu6.5 deb +dunder-proto 1.0.1 npm +e2fsprogs 1.47.0-2.4~exp1ubuntu4.1 deb +ee-first 1.1.1 npm +emmet 1.0.0 npm +encodeurl 2.0.0 npm +end-of-stream 1.4.4 npm +env-paths 2.2.1 npm +es-define-property 1.0.1 npm +es-errors 1.3.0 npm +es-object-atoms 1.1.1 npm +es6-promisify 7.0.0 npm +escape-html 1.0.3 npm +escodegen 2.1.0 npm +esprima 4.0.1 npm +estraverse 5.3.0 npm +esutils 2.0.3 npm +etag 1.8.1 npm +eventemitter3 4.0.7 npm +expand-template 2.0.3 npm +express 5.2.0 npm +extension-editing 1.0.0 npm +fd-slicer 1.1.0 npm +file-uri-to-path 1.0.0 npm +finalhandler 2.1.0 npm +findutils 4.9.0-5build1 deb +follow-redirects 1.15.9 npm +forwarded 0.2.0 npm +fresh 2.0.0 npm +fs-constants 1.0.0 npm +fs-extra 11.2.0 npm +fsharp 1.0.0 npm +function-bind 1.1.2 npm +gcc-14-base 14.2.0-4ubuntu2~24.04.1 deb +get-intrinsic 1.3.0 npm +get-proto 1.0.1 npm +get-uri 6.0.4 npm +git 1.0.0 npm +git 1:2.43.0-1ubuntu7.3 deb +git-base 1.0.0 npm +git-man 1:2.43.0-1ubuntu7.3 deb +github 0.0.1 npm +github-authentication 0.0.2 npm +github-from-package 0.0.0 npm +gnupg 2.4.4-2ubuntu17.4 deb +gnupg-l10n 2.4.4-2ubuntu17.4 deb +gnupg-utils 2.4.4-2ubuntu17.4 deb +go 1.0.0 npm +gopd 1.2.0 npm +gpg 2.4.4-2ubuntu17.4 deb +gpg-agent 2.4.4-2ubuntu17.4 deb +gpg-wks-client 2.4.4-2ubuntu17.4 deb +gpgconf 2.4.4-2ubuntu17.4 deb +gpgsm 2.4.4-2ubuntu17.4 deb +gpgv 2.4.4-2ubuntu17.4 deb +graceful-fs 4.2.11 npm +grep 3.11-4build1 deb +groovy 1.0.0 npm +grunt 1.0.0 npm +gulp 1.0.0 npm +gzip 1.12-1ubuntu3.1 deb +handlebars 1.0.0 npm +has-symbols 1.1.0 npm +hasown 2.0.2 npm +hlsl 1.0.0 npm +hostname 3.23+nmu2ubuntu2 deb +html 1.0.0 npm +html-language-features 1.0.0 npm +http-errors 2.0.1 npm +http-proxy 1.18.1 npm +http-proxy-agent 7.0.0 npm +http-proxy-agent 7.0.2 npm +httpolyglot 0.1.2 npm +https-proxy-agent 7.0.2 npm +https-proxy-agent 7.0.6 npm (+1 duplicate) +i18next 25.3.0 npm +iconv-lite 0.7.2 npm +ieee754 1.2.1 npm +inherits 2.0.4 npm (+1 duplicate) +ini 1.0.0 npm +ini 1.3.8 npm +init-system-helpers 1.66ubuntu1 deb +ip-address 9.0.5 npm (+1 duplicate) +ipaddr.js 1.9.1 npm +ipynb 1.0.0 npm +is-buffer 1.1.6 npm +is-extglob 2.1.1 npm +is-glob 4.0.3 npm +is-promise 4.0.0 npm +isexe 2.0.0 npm +jake 1.0.0 npm +java 1.0.0 npm +javascript 1.0.0 npm +jq 1.7.1-3ubuntu0.24.04.1 deb +js-base64 3.7.7 npm +js-debug 1.105.0 npm +js-debug-companion 1.1.3 npm +js-yaml 4.1.1 npm +jsbn 1.1.0 npm (+1 duplicate) +jschardet 3.1.4 npm +json 1.0.0 npm +json-language-features 1.0.0 npm +jsonfile 6.1.0 npm +julia 1.0.0 npm +just-performance 4.3.0 npm +katex 0.16.22 npm +kerberos 2.1.1 npm +keyboxd 2.4.4-2ubuntu17.4 deb +krb5-locales 1.20.1-6ubuntu2.6 deb +latex 1.0.0 npm +less 1.0.0 npm +less 590-2ubuntu2.1 deb +libacl1 2.3.2-1build1.1 deb +libapparmor1 4.0.1really4.0.1-0ubuntu0.24.04.5 deb +libapt-pkg6.0t64 2.8.3 deb +libassuan0 2.5.6-1build1 deb +libatomic1 14.2.0-4ubuntu2~24.04.1 deb +libattr1 1:2.5.2-1build1.1 deb +libaudit-common 1:3.1.2-2.1build1.1 deb +libaudit1 1:3.1.2-2.1build1.1 deb +libblkid1 2.39.3-9ubuntu6.4 deb +libbrotli1 1.1.0-2build2 deb +libbsd0 0.12.1-1build1.1 deb +libbz2-1.0 1.0.8-5.1build0.1 deb +libc-bin 2.39-0ubuntu8.7 deb +libc6 2.39-0ubuntu8.7 deb +libcap-ng0 0.8.4-2build2 deb +libcap2 1:2.66-5ubuntu2.2 deb +libcbor0.10 0.10.2-1.2ubuntu2 deb +libcom-err2 1.47.0-2.4~exp1ubuntu4.1 deb +libcrypt1 1:4.4.36-4build1 deb +libcurl3t64-gnutls 8.5.0-2ubuntu10.7 deb +libcurl4t64 8.5.0-2ubuntu10.7 deb +libdb5.3t64 5.3.28+dfsg2-7 deb +libdebconfclient0 0.271ubuntu3 deb +libedit2 3.1-20230828-1build1 deb +liberror-perl 0.17029-2 deb +libexpat1 2.6.1-2ubuntu0.4 deb +libext2fs2t64 1.47.0-2.4~exp1ubuntu4.1 deb +libffi8 3.4.6-1build1 deb +libfido2-1 1.14.0-1build3 deb +libgcc-s1 14.2.0-4ubuntu2~24.04.1 deb +libgcrypt20 1.10.3-2build1 deb +libgdbm-compat4t64 1.23-5.1build1 deb +libgdbm6t64 1.23-5.1build1 deb +libgmp10 2:6.3.0+dfsg-2ubuntu6.1 deb +libgnutls30t64 3.8.3-1.1ubuntu3.5 deb +libgpg-error0 1.47-3build2.1 deb +libgssapi-krb5-2 1.20.1-6ubuntu2.6 deb +libhogweed6t64 3.9.1-2.2build1.1 deb +libidn2-0 2.3.7-2build1.1 deb +libjq1 1.7.1-3ubuntu0.24.04.1 deb +libk5crypto3 1.20.1-6ubuntu2.6 deb +libkeyutils1 1.6.3-3build1 deb +libkrb5-3 1.20.1-6ubuntu2.6 deb +libkrb5support0 1.20.1-6ubuntu2.6 deb +libksba8 1.6.6-1build1 deb +libldap-common 2.6.10+dfsg-0ubuntu0.24.04.1 deb +libldap2 2.6.10+dfsg-0ubuntu0.24.04.1 deb +liblz4-1 1.9.4-1build1.1 deb +liblzma5 5.6.1+really5.4.5-1ubuntu0.2 deb +libmd0 1.1.0-2build1.1 deb +libmount1 2.39.3-9ubuntu6.4 deb +libncursesw6 6.4+20240113-1ubuntu2 deb +libnettle8t64 3.9.1-2.2build1.1 deb +libnghttp2-14 1.59.0-1ubuntu0.2 deb +libnpth0t64 1.6-3.1build1 deb +libonig5 6.9.9-1build1 deb +libp11-kit0 0.25.3-4ubuntu2.1 deb +libpam-modules 1.5.3-5ubuntu5.5 deb +libpam-modules-bin 1.5.3-5ubuntu5.5 deb +libpam-runtime 1.5.3-5ubuntu5.5 deb +libpam0g 1.5.3-5ubuntu5.5 deb +libpcre2-8-0 10.42-4ubuntu2.1 deb +libperl5.38t64 5.38.2-3.2ubuntu0.2 deb +libproc2-0 2:4.0.4-4ubuntu3.2 deb +libpsl5t64 0.21.2-1.1build1 deb +libreadline8t64 8.2-4build1 deb +librtmp1 2.4+20151223.gitfa8646d.1-2build7 deb +libsasl2-2 2.1.28+dfsg1-5ubuntu3.1 deb +libsasl2-modules 2.1.28+dfsg1-5ubuntu3.1 deb +libsasl2-modules-db 2.1.28+dfsg1-5ubuntu3.1 deb +libseccomp2 2.5.5-1ubuntu3.1 deb +libselinux1 3.5-2ubuntu2.1 deb +libsemanage-common 3.5-1build5 deb +libsemanage2 3.5-1build5 deb +libsepol2 3.5-2build1 deb +libsmartcols1 2.39.3-9ubuntu6.4 deb +libsqlite3-0 3.45.1-1ubuntu2.5 deb +libss2 1.47.0-2.4~exp1ubuntu4.1 deb +libssh-4 0.10.6-2ubuntu0.3 deb +libssl3t64 3.0.13-0ubuntu3.7 deb +libstdc++6 14.2.0-4ubuntu2~24.04.1 deb +libsystemd0 255.4-1ubuntu8.12 deb +libtasn1-6 4.19.0-3ubuntu0.24.04.2 deb +libtinfo6 6.4+20240113-1ubuntu2 deb +libudev1 255.4-1ubuntu8.12 deb +libunistring5 1.1-2build1.1 deb +libuuid1 2.39.3-9ubuntu6.4 deb +libx11-6 2:1.8.7-1build1 deb +libx11-data 2:1.8.7-1build1 deb +libxau6 1:1.0.9-1build6 deb +libxcb1 1.15-1ubuntu2 deb +libxdmcp6 1:1.1.3-0ubuntu6 deb +libxext6 2:1.3.4-1build2 deb +libxmuu1 2:1.1.3-3build2 deb +libxxhash0 0.8.2-2build1 deb +libzstd1 1.5.5+dfsg2-2build1.1 deb +limiter 2.1.0 npm +locales 2.39-0ubuntu8.7 deb +lodash-es 4.17.23 npm +log 1.0.0 npm +login 1:4.13+dfsg1-4ubuntu3.2 deb +logsave 1.47.0-2.4~exp1ubuntu4.1 deb +lru-cache 6.0.0 npm +lru-cache 7.18.3 npm +lua 1.0.0 npm +make 1.0.0 npm +markdown 1.0.0 npm +markdown-language-features 1.0.0 npm +markdown-math 1.0.0 npm +math-intrinsics 1.1.0 npm +mawk 1.3.4.20240123-1build1 deb +md5 2.3.0 npm +media-preview 1.0.0 npm +media-typer 1.1.0 npm +merge-conflict 1.0.0 npm +merge-descriptors 2.0.0 npm +mermaid-chat-features 1.0.0 npm +microsoft-authentication 0.0.1 npm +mime-db 1.54.0 npm +mime-types 3.0.1 npm +mimic-response 3.1.0 npm +minimist 1.2.8 npm +mkdirp 1.0.4 npm +mkdirp-classic 0.5.3 npm +mount 2.39.3-9ubuntu6.4 deb +ms 2.0.0 npm +ms 2.1.2 npm +ms 2.1.3 npm +nano 7.2-2ubuntu0.1 deb +napi-build-utils 1.0.2 npm +ncurses-base 6.4+20240113-1ubuntu2 deb +ncurses-bin 6.4+20240113-1ubuntu2 deb +negotiator 0.6.4 npm +negotiator 1.0.0 npm +net-tools 2.10-0.1ubuntu4.4 deb +netbase 6.4 deb +netcat-openbsd 1.226-1ubuntu2 deb +netmask 2.0.2 npm +node 22.21.1 binary +node-abi 3.8.0 npm +node-addon-api 7.1.0 npm +node-addon-api 8.5.0 npm +node-gyp-build 4.8.4 npm +node-pty 1.2.0-beta.10 npm +npm 1.0.1 npm +object-inspect 1.13.4 npm +objective-c 1.0.0 npm +on-finished 2.4.1 npm +on-headers 1.1.0 npm +once 1.4.0 npm (+1 duplicate) +openssh-client 1:9.6p1-3ubuntu13.14 deb +openssl 3.0.13-0ubuntu3.7 deb +opentype.js 0.8.0 npm +os-tmpdir 1.0.2 npm +pac-proxy-agent 7.2.0 npm +pac-resolver 7.0.1 npm +parseurl 1.3.3 npm +passwd 1:4.13+dfsg1-4ubuntu3.2 deb +patch 2.7.6-7build3 deb +path-key 3.1.1 npm +path-to-regexp 8.3.0 npm +pem 1.14.8 npm +pend 1.2.0 npm +perl 1.0.0 npm +perl 5.38.2-3.2ubuntu0.2 deb +perl-base 5.38.2-3.2ubuntu0.2 deb +perl-modules-5.38 5.38.2-3.2ubuntu0.2 deb +php 1.0.0 npm +php-language-features 1.0.0 npm +picomatch 4.0.3 npm +pinentry-curses 1.2.1-3ubuntu5 deb +powershell 1.0.0 npm +prebuild-install 7.1.2 npm +procps 2:4.0.4-4ubuntu3.2 deb +prompt 1.0.0 npm +proxy-addr 2.0.7 npm +proxy-agent 6.5.0 npm +proxy-from-env 1.1.0 npm (+1 duplicate) +publicsuffix 20231001.0357-0.1 deb +pug 1.0.0 npm +pump 3.0.0 npm +python 1.0.0 npm +qs 6.14.1 npm +r 1.0.0 npm +range-parser 1.2.1 npm +raw-body 3.0.2 npm +razor 1.0.0 npm +rc 1.2.8 npm +readable-stream 3.6.0 npm +readline-common 8.2-4build1 deb +references-view 1.0.0 npm +requires-port 1.0.0 npm +restructuredtext 1.0.0 npm +rotating-file-stream 3.2.5 npm +router 2.2.0 npm +ruby 1.0.0 npm +rust 1.0.0 npm +safe-buffer 5.2.1 npm (+1 duplicate) +safe-compare 1.1.4 npm +safer-buffer 2.1.2 npm +scss 1.0.0 npm +search-result 1.0.0 npm +sed 4.9-2build1 deb +semver 7.5.4 npm +semver 7.7.1 npm +send 1.2.0 npm +sensible-utils 0.0.22 deb +serve-static 2.2.0 npm +setprototypeof 1.2.0 npm +shaderlab 1.0.0 npm +shebang-command 2.0.0 npm +shebang-regex 3.0.0 npm +shell-quote 1.8.3 npm +shellscript 1.0.0 npm +side-channel 1.1.0 npm +side-channel-list 1.0.0 npm +side-channel-map 1.0.1 npm +side-channel-weakmap 1.0.2 npm +simple-browser 1.0.0 npm +simple-concat 1.0.1 npm +simple-get 4.0.1 npm +smart-buffer 4.2.0 npm (+1 duplicate) +socks 2.8.3 npm +socks 2.8.4 npm +socks-proxy-agent 8.0.4 npm +socks-proxy-agent 8.0.5 npm +source-map 0.6.1 npm +sprintf-js 1.1.3 npm (+1 duplicate) +sql 1.0.0 npm +statuses 2.0.2 npm +string_decoder 1.3.0 npm +strip-json-comments 2.0.1 npm +sudo 1.9.15p5-3ubuntu5.24.04.1 deb +swift 1.0.0 npm +systemd-standalone-sysusers 255.4-1ubuntu8.12 deb +sysvinit-utils 3.08-6ubuntu3 deb +tar 1.35+dfsg-3build1 deb +tar-fs 2.1.4 npm +tar-stream 2.2.0 npm +tas-client 0.3.1 npm +terminal-suggest 1.0.1 npm +theme-2026 0.1.0 npm +theme-abyss 1.0.0 npm +theme-defaults 1.0.0 npm +theme-kimbie-dark 1.0.0 npm +theme-monokai 1.0.0 npm +theme-monokai-dimmed 1.0.0 npm +theme-quietlight 1.0.0 npm +theme-red 1.0.0 npm +theme-solarized-dark 1.0.0 npm +theme-solarized-light 1.0.0 npm +theme-tomorrow-night-blue 1.0.0 npm +tiny-inflate 1.0.3 npm +toidentifier 1.0.1 npm +tslib 2.8.1 npm (+1 duplicate) +tunnel-agent 0.6.0 npm +tunnel-forwarding 1.0.0 npm +type-is 2.0.1 npm +typescript 1.0.0 npm +typescript 5.8.3 npm +typescript 5.9.3 npm +typescript-language-features 1.0.0 npm +tzdata 2025b-0ubuntu0.24.04.1 deb +ubuntu-keyring 2023.11.28.1 deb +undici 7.19.0 npm +universalify 2.0.1 npm +unminimize 0.2.1 deb +unpipe 1.0.0 npm +util-deprecate 1.0.2 npm +util-linux 2.39.3-9ubuntu6.4 deb +uuid 9.0.1 npm +vary 1.1.2 npm +vb 1.0.0 npm +vscode-css-languageserver 1.0.0 npm +vscode-extensions 0.0.1 npm +vscode-html-languageserver 1.0.0 npm +vscode-js-profile-table 1.0.10 npm +vscode-json-languageserver 1.3.4 npm +vscode-oniguruma 1.7.0 npm +vscode-regexpp 3.1.0 npm +vscode-textmate 9.3.2 npm +vscode-theme-seti 1.0.0 npm +which 2.0.2 npm +wrappy 1.0.2 npm (+1 duplicate) +ws 8.18.0 npm +xauth 1:1.1.2-1build1 deb +xdg-basedir 4.0.0 npm +xml 1.0.0 npm +yallist 4.0.0 npm +yaml 1.0.0 npm +yauzl 2.10.0 npm +yauzl 3.1.1 npm +yazl 2.4.3 npm +zlib1g 1:1.3.dfsg-3.1ubuntu2.1 deb +zod 3.25.76 npm diff --git a/readme-vars.yml b/readme-vars.yml index 24ab5398..3996ca39 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -4,59 +4,46 @@ project_name: code-server project_url: "https://coder.com" project_logo: "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/code-server-banner.png" -project_blurb: "[{{ project_name|capitalize }}]({{ project_url }}) is VS Code running on a remote server, accessible through the browser. - -- Code on your Chromebook, tablet, and laptop with a consistent dev environment. - -- If you have a Windows or Mac workstation, more easily develop for Linux. - -- Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - -- Preserve battery life when you're on the go. - -- All intensive computation runs on your server. - -- You're no longer running excess instances of Chrome." +project_blurb: | + [{{ project_name|capitalize }}]({{ project_url }}) is VS Code running on a remote server, accessible through the browser. + - Code on your Chromebook, tablet, and laptop with a consistent dev environment. + - If you have a Windows or Mac workstation, more easily develop for Linux. + - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. + - Preserve battery life when you're on the go. + - All intensive computation runs on your server. + - You're no longer running excess instances of Chrome. project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}" - +project_categories: "Programming" # supported architectures available_architectures: - - { arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} - - { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} - - { arch: "{{ arch_armhf }}", tag: "arm32v7-latest"} - -# development version -development_versions: true -development_versions_items: - - { tag: "latest", desc: "Stable releases" } - - { tag: "focal", desc: "Stable releases, based on Ubuntu Focal" } - - { tag: "development", desc: "DEPRECATED (no longer updated) - Prereleases from their GitHub" } - + - {arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} + - {arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} # container parameters common_param_env_vars_enabled: true param_container_name: "{{ project_name }}" param_usage_include_vols: true param_volumes: - - { vol_path: "/config", vol_host_path: "/path/to/appdata/config", desc: "Contains all relevant configuration files." } + - {vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Contains all relevant configuration files."} param_usage_include_ports: true param_ports: - - { external_port: "8443", internal_port: "8443", port_desc: "web gui" } -param_usage_include_env: true -param_env_vars: - - { env_var: "TZ", env_value: "Europe/London", desc: "Specify a timezone to use EG Europe/London" } - + - {external_port: "8443", internal_port: "8443", port_desc: "web gui"} # optional container parameters opt_param_usage_include_env: true opt_param_env_vars: - - { env_var: "PASSWORD", env_value: "password", desc: "Optional web gui password, if `PASSWORD` or `HASHED_PASSWORD` is not provided, there will be no auth." } - - { env_var: "HASHED_PASSWORD", env_value: "", desc: "Optional web gui password, overrides `PASSWORD`, instructions on how to create it is below." } - - { env_var: "SUDO_PASSWORD", env_value: "password", desc: "If this optional variable is set, user will have sudo access in the code-server terminal with the specified password." } - - { env_var: "SUDO_PASSWORD_HASH", env_value: "", desc: "Optionally set sudo password via hash (takes priority over `SUDO_PASSWORD` var). Format is `$type$salt$hashed`." } - - { env_var: "PROXY_DOMAIN", env_value: "code-server.my.domain", desc: "If this optional variable is set, this domain will be proxied for subdomain proxying. See [Documentation](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#sub-domains)" } - -optional_block_1: false -optional_block_1_items: "" - + - {env_var: "PASSWORD", env_value: "password", desc: "Optional web gui password, if `PASSWORD` or `HASHED_PASSWORD` is not provided, there will be no auth."} + - {env_var: "HASHED_PASSWORD", env_value: "", desc: "Optional web gui password, overrides `PASSWORD`, instructions on how to create it is below."} + - {env_var: "SUDO_PASSWORD", env_value: "password", desc: "If this optional variable is set, user will have sudo access in the code-server terminal with the specified password."} + - {env_var: "SUDO_PASSWORD_HASH", env_value: "", desc: "Optionally set sudo password via hash (takes priority over `SUDO_PASSWORD` var). Format is `$type$salt$hashed`."} + - {env_var: "PROXY_DOMAIN", env_value: "code-server.my.domain", desc: "If this optional variable is set, this domain will be proxied for subdomain proxying. See [Documentation](https://github.com/coder/code-server/blob/main/docs/guide.md#using-a-subdomain)"} + - {env_var: "DEFAULT_WORKSPACE", env_value: "/config/workspace", desc: "If this optional variable is set, code-server will open this directory by default"} + - {env_var: "PWA_APPNAME", env_value: "code-server", desc: "If this optional variable is set, the PWA app will the specified name."} +readonly_supported: true +readonly_message: | + * `/tmp` must be mounted to tmpfs + * `sudo` will not be available +nonroot_supported: true +nonroot_message: | + * `sudo` will not be available # application setup block app_setup_block_enabled: true app_setup_block: | @@ -72,24 +59,75 @@ app_setup_block: | ### Hashed code-server password How to create the [hashed password](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#can-i-store-my-password-hashed). - - +# init diagram +init_diagram: | + "code-server:latest": { + docker-mods + base { + fix-attr +\nlegacy cont-init + } + docker-mods -> base + legacy-services + custom services + init-services -> legacy-services + init-services -> custom services + custom services -> legacy-services + legacy-services -> ci-service-check + init-migrations -> init-adduser + init-config -> init-code-server + init-os-end -> init-config + init-code-server -> init-config-end + init-config -> init-config-end + init-crontab-config -> init-config-end + init-config -> init-crontab-config + init-mods-end -> init-custom-files + init-adduser -> init-device-perms + base -> init-envfile + base -> init-migrations + init-config-end -> init-mods + init-mods-package-install -> init-mods-end + init-mods -> init-mods-package-install + init-adduser -> init-os-end + init-device-perms -> init-os-end + init-envfile -> init-os-end + init-custom-files -> init-services + init-services -> svc-code-server + svc-code-server -> legacy-services + init-services -> svc-cron + svc-cron -> legacy-services + } + Base Images: { + "baseimage-ubuntu:noble" + } + "code-server:latest" <- Base Images # changelog changelogs: - - { date: "16.09.21:", desc: "Fix slow `chown` on large workspace (contents of workspace folder no longer chowned)." } - - { date: "11.07.21:", desc: "Bump node to 14 to fix builds" } - - { date: "08.05.21:", desc: "Fix doc link" } - - { date: "04.02.20:", desc: "Allow setting gui password via hash using env var `HASHED_PASSWORD`." } - - { date: "23.12.20:", desc: "Allow setting sudo password via hash using env var `SUDO_PASSWORD_HASH`." } - - { date: "29.05.20:", desc: "Add --domain-proxy support." } - - { date: "21.05.20:", desc: "Shrink images, install via yarn, fix arm32v7 build." } - - { date: "18.05.20:", desc: "Switch to multi-arch images, install via npm." } - - { date: "29.04.20:", desc: "Update start arguments." } - - { date: "01.04.20:", desc: "Structural changes required for v3." } - - { date: "17.01.20:", desc: "Fix artifact url retrieval from github." } - - { date: "24.10.19:", desc: "Upgrade to v2 builds." } - - { date: "28.09.19:", desc: "Update project logo." } - - { date: "21.09.19:", desc: "Add development builds/tag." } - - { date: "09.07.19:", desc: "Add optional sudo access." } - - { date: "01.07.19:", desc: "Add nano." } - - { date: "24.06.19:", desc: "Initial Release." } + - {date: "10.08.25:", desc: "Let server listen on both ipv4 and ipv6."} + - {date: "03.06.25:", desc: "Allow setting PWA name using env var `PWA_APPNAME`."} + - {date: "13.10.24:", desc: "Only chown config folder when change to ownership or new install is detected."} + - {date: "09.10.24:", desc: "Manage permissions in /config/.ssh according to file type"} + - {date: "19.08.24:", desc: "Rebase to Ubuntu Noble."} + - {date: "01.07.23:", desc: "Deprecate armhf. As announced [here](https://www.linuxserver.io/blog/a-farewell-to-arm-hf)"} + - {date: "05.10.22:", desc: "Install recommended deps to maintain parity with the older images."} + - {date: "29.09.22:", desc: "Rebase to jammy, switch to s6v3. Fix chown logic to skip `/config/workspace` contents."} + - {date: "20.02.22:", desc: "Install using the official tarballs."} + - {date: "29.12.21:", desc: "Add `install-extension` as a helper for mods to install extensions."} + - {date: "06.12.21:", desc: "Add `DEFAULT_WORKSPACE` env var."} + - {date: "29.11.21:", desc: "Rebase to Ubuntu focal."} + - {date: "16.09.21:", desc: "Fix slow `chown` on large workspace (contents of workspace folder no longer chowned)."} + - {date: "11.07.21:", desc: "Bump node to 14 to fix builds"} + - {date: "08.05.21:", desc: "Fix doc link"} + - {date: "04.02.20:", desc: "Allow setting gui password via hash using env var `HASHED_PASSWORD`."} + - {date: "23.12.20:", desc: "Allow setting sudo password via hash using env var `SUDO_PASSWORD_HASH`."} + - {date: "29.05.20:", desc: "Add --domain-proxy support."} + - {date: "21.05.20:", desc: "Shrink images, install via yarn, fix arm32v7 build."} + - {date: "18.05.20:", desc: "Switch to multi-arch images, install via npm."} + - {date: "29.04.20:", desc: "Update start arguments."} + - {date: "01.04.20:", desc: "Structural changes required for v3."} + - {date: "17.01.20:", desc: "Fix artifact url retrieval from github."} + - {date: "24.10.19:", desc: "Upgrade to v2 builds."} + - {date: "28.09.19:", desc: "Update project logo."} + - {date: "21.09.19:", desc: "Add development builds/tag."} + - {date: "09.07.19:", desc: "Add optional sudo access."} + - {date: "01.07.19:", desc: "Add nano."} + - {date: "24.06.19:", desc: "Initial Release."} diff --git a/root/etc/cont-init.d/30-config b/root/etc/cont-init.d/30-config deleted file mode 100644 index 1c09036b..00000000 --- a/root/etc/cont-init.d/30-config +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/with-contenv bash - -mkdir -p /config/{extensions,data,workspace,.ssh} - -if [ -n "${SUDO_PASSWORD}" ] || [ -n "${SUDO_PASSWORD_HASH}" ]; then - echo "setting up sudo access" - if ! grep -q 'abc' /etc/sudoers; then - echo "adding abc to sudoers" - echo "abc ALL=(ALL:ALL) ALL" >> /etc/sudoers - fi - if [ -n "${SUDO_PASSWORD_HASH}" ]; then - echo "setting sudo password using sudo password hash" - sed -i "s|^abc:\!:|abc:${SUDO_PASSWORD_HASH}:|" /etc/shadow - else - echo "setting sudo password using SUDO_PASSWORD env var" - echo -e "${SUDO_PASSWORD}\n${SUDO_PASSWORD}" | passwd abc - fi -fi - -# permissions -if [ -f "/usr/bin/find" ] && [ -f "/usr/bin/xargs" ]; then - CORES=$(nproc --all) - - # Split workload between config and workspace - echo "setting permissions::configuration" - find /config -path /config/workspace -prune -false -o -type d -print0 | \ - xargs --null -r --max-args=1 --max-procs=$((CORES*2*8)) \ - chown -R abc:abc - - echo "setting permissions::workspace" - chown abc:abc /config/workspace -else - # Set permissions on data mount - # do not decend into the workspace - chown -R abc:abc "$(ls /config -I workspace)" - chown abc:abc /config/workspace -fi diff --git a/root/etc/s6-overlay/s6-rc.d/init-code-server/dependencies.d/init-config b/root/etc/s6-overlay/s6-rc.d/init-code-server/dependencies.d/init-config new file mode 100644 index 00000000..e69de29b diff --git a/root/etc/s6-overlay/s6-rc.d/init-code-server/run b/root/etc/s6-overlay/s6-rc.d/init-code-server/run new file mode 100755 index 00000000..8b42ed0b --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-code-server/run @@ -0,0 +1,46 @@ +#!/usr/bin/with-contenv bash +# shellcheck shell=bash + +mkdir -p /config/{extensions,data,workspace,.ssh} + +if [[ -z ${LSIO_NON_ROOT_USER} ]] && [[ -z ${LSIO_READ_ONLY_FS} ]]; then + if [[ -n "${SUDO_PASSWORD}" ]] || [[ -n "${SUDO_PASSWORD_HASH}" ]]; then + echo "setting up sudo access" + if ! grep -q 'abc' /etc/sudoers; then + echo "adding abc to sudoers" + echo "abc ALL=(ALL:ALL) ALL" >> /etc/sudoers + fi + if [[ -n "${SUDO_PASSWORD_HASH}" ]]; then + echo "setting sudo password using sudo password hash" + sed -i "s|^abc:\!:|abc:${SUDO_PASSWORD_HASH}:|" /etc/shadow + else + echo "setting sudo password using SUDO_PASSWORD env var" + echo -e "${SUDO_PASSWORD}\n${SUDO_PASSWORD}" | passwd abc + fi + fi +fi + +if [[ ! -f /config/.bashrc ]]; then + cp /root/.bashrc /config/.bashrc +fi + +if [[ ! -f /config/.profile ]]; then + cp /root/.profile /config/.profile +fi + +if [[ -z ${LSIO_NON_ROOT_USER} ]]; then + # fix permissions (ignore contents of workspace) + PUID=${PUID:-911} + if [[ ! "$(stat -c %u /config/.profile)" == "${PUID}" ]]; then + echo "Change in ownership or new install detected, please be patient while we chown existing files" + echo "This could take some time" + find /config -path "/config/workspace" -prune -o -exec lsiown abc:abc {} + + lsiown abc:abc /config/workspace + fi + chmod 700 /config/.ssh + if [[ -n "$(ls -A /config/.ssh)" ]]; then + find /config/.ssh/ -type d -exec chmod 700 '{}' \; + find /config/.ssh/ -type f -exec chmod 600 '{}' \; + find /config/.ssh/ -type f -iname '*.pub' -exec chmod 644 '{}' \; + fi +fi diff --git a/root/etc/s6-overlay/s6-rc.d/init-code-server/type b/root/etc/s6-overlay/s6-rc.d/init-code-server/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-code-server/type @@ -0,0 +1 @@ +oneshot diff --git a/root/etc/s6-overlay/s6-rc.d/init-code-server/up b/root/etc/s6-overlay/s6-rc.d/init-code-server/up new file mode 100644 index 00000000..3b22ac91 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/init-code-server/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/init-code-server/run diff --git a/root/etc/s6-overlay/s6-rc.d/init-config-end/dependencies.d/init-code-server b/root/etc/s6-overlay/s6-rc.d/init-config-end/dependencies.d/init-code-server new file mode 100644 index 00000000..e69de29b diff --git a/root/etc/s6-overlay/s6-rc.d/svc-code-server/dependencies.d/init-services b/root/etc/s6-overlay/s6-rc.d/svc-code-server/dependencies.d/init-services new file mode 100644 index 00000000..e69de29b diff --git a/root/etc/s6-overlay/s6-rc.d/svc-code-server/notification-fd b/root/etc/s6-overlay/s6-rc.d/svc-code-server/notification-fd new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-code-server/notification-fd @@ -0,0 +1 @@ +3 diff --git a/root/etc/s6-overlay/s6-rc.d/svc-code-server/run b/root/etc/s6-overlay/s6-rc.d/svc-code-server/run new file mode 100755 index 00000000..d8a6e224 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-code-server/run @@ -0,0 +1,46 @@ +#!/usr/bin/with-contenv bash +# shellcheck shell=bash + +if [[ -n "${PASSWORD}" ]] || [[ -n "${HASHED_PASSWORD}" ]]; then + AUTH="password" +else + AUTH="none" + echo "starting with no password" +fi + +if [[ -z ${PROXY_DOMAIN+x} ]]; then + PROXY_DOMAIN_ARG="" +else + PROXY_DOMAIN_ARG="--proxy-domain=${PROXY_DOMAIN}" +fi + +if [[ -z ${PWA_APPNAME} ]]; then + PWA_APPNAME="code-server" +fi + +if [[ -z ${LSIO_NON_ROOT_USER} ]]; then + exec \ + s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z 127.0.0.1 8443" \ + s6-setuidgid abc \ + /app/code-server/bin/code-server \ + --bind-addr 0.0.0.0:8443 \ + --user-data-dir /config/data \ + --extensions-dir /config/extensions \ + --disable-telemetry \ + --auth "${AUTH}" \ + --app-name "${PWA_APPNAME}" \ + "${PROXY_DOMAIN_ARG}" \ + "${DEFAULT_WORKSPACE:-/config/workspace}" +else + exec \ + s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z 127.0.0.1 8443" \ + /app/code-server/bin/code-server \ + --bind-addr "[::]:8443" \ + --user-data-dir /config/data \ + --extensions-dir /config/extensions \ + --disable-telemetry \ + --auth "${AUTH}" \ + --app-name "${PWA_APPNAME}" \ + "${PROXY_DOMAIN_ARG}" \ + "${DEFAULT_WORKSPACE:-/config/workspace}" +fi diff --git a/root/etc/s6-overlay/s6-rc.d/svc-code-server/type b/root/etc/s6-overlay/s6-rc.d/svc-code-server/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-code-server/type @@ -0,0 +1 @@ +longrun diff --git a/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-code-server b/root/etc/s6-overlay/s6-rc.d/user/contents.d/init-code-server new file mode 100644 index 00000000..e69de29b diff --git a/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-code-server b/root/etc/s6-overlay/s6-rc.d/user/contents.d/svc-code-server new file mode 100644 index 00000000..e69de29b diff --git a/root/etc/services.d/code-server/run b/root/etc/services.d/code-server/run deleted file mode 100644 index c298a9b4..00000000 --- a/root/etc/services.d/code-server/run +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/with-contenv bash - -if [ -n "${PASSWORD}" ] || [ -n "${HASHED_PASSWORD}" ]; then - AUTH="password" -else - AUTH="none" - echo "starting with no password" -fi - -if [ -z ${PROXY_DOMAIN+x} ]; then - PROXY_DOMAIN_ARG="" -else - PROXY_DOMAIN_ARG="--proxy-domain=${PROXY_DOMAIN}" -fi - -exec \ - s6-setuidgid abc \ - /usr/local/bin/code-server \ - --bind-addr 0.0.0.0:8443 \ - --user-data-dir /config/data \ - --extensions-dir /config/extensions \ - --disable-telemetry \ - --auth "${AUTH}" \ - "${PROXY_DOMAIN_ARG}" \ - /config/workspace diff --git a/root/usr/local/bin/install-extension b/root/usr/local/bin/install-extension new file mode 100755 index 00000000..48dfbb20 --- /dev/null +++ b/root/usr/local/bin/install-extension @@ -0,0 +1,10 @@ +#!/usr/bin/with-contenv bash +# shellcheck shell=bash + +_install=(/app/code-server/bin/code-server "--extensions-dir" "/config/extensions" "--install-extension") + +if [[ "$(whoami)" == "abc" ]]; then + "${_install[@]}" "$@" +else + s6-setuidgid abc "${_install[@]}" "$@" +fi