Compare commits
No commits in common. "master" and "v1.9.4" have entirely different histories.
|
@ -0,0 +1,288 @@
|
||||||
|
[0.1.0]
|
||||||
|
* Initial package (forked from Gogs app)
|
||||||
|
|
||||||
|
[0.1.1]
|
||||||
|
* Removed reference to Gogs
|
||||||
|
|
||||||
|
[0.1.2]
|
||||||
|
* Updated description
|
||||||
|
|
||||||
|
[0.1.3]
|
||||||
|
* Updated to version 1.1.2
|
||||||
|
|
||||||
|
[1.0.0]
|
||||||
|
* Update to version 1.1.3
|
||||||
|
|
||||||
|
[1.0.1]
|
||||||
|
* Update Git to v2.7.4-0ubuntu1.2
|
||||||
|
* Fixes critical security issue that allows remote command execution in git
|
||||||
|
* https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-1000117.html
|
||||||
|
|
||||||
|
[1.0.2]
|
||||||
|
* Preserve SECRET_KEY across updates and restarts
|
||||||
|
|
||||||
|
[1.0.3]
|
||||||
|
* Update to version 1.1.4
|
||||||
|
|
||||||
|
[1.1.0]
|
||||||
|
* Update to version 1.2.0
|
||||||
|
* New logo!
|
||||||
|
* SECURITY: Sanitation fix from Gogs (#1461)
|
||||||
|
* Status-API
|
||||||
|
* Implement GPG api
|
||||||
|
* https://github.com/go-gitea/gitea/releases/tag/v1.2.0
|
||||||
|
|
||||||
|
[1.1.1]
|
||||||
|
* Update to version 1.2.1
|
||||||
|
* Fix PR, milestone and label functionality if issue unit is disabled (#2710) (#2714)
|
||||||
|
* Fix plain readme didn't render correctly on repo home page (#2705) (#2712)
|
||||||
|
* Fix so that user can still fork his own repository to his organizations (#2699) (#2707)
|
||||||
|
* Fix .netrc authentication (#2700) (#2708)
|
||||||
|
* Fix slice out of bounds error in mailer (#2479) (#2696)
|
||||||
|
|
||||||
|
[1.1.2]
|
||||||
|
* Update to version 1.2.2
|
||||||
|
* Add checks for commits with missing author and time (#2771) (#2785)
|
||||||
|
* Fix sending mail with a non-latin display name (#2559) (#2783)
|
||||||
|
* Sync MaxGitDiffLineCharacters with conf/app.ini (#2779) (#2780)
|
||||||
|
* Update vendor git (#2765) (#2772)
|
||||||
|
* Fix emojify image URL (#2769) (#2773)
|
||||||
|
|
||||||
|
[1.1.3]
|
||||||
|
* Update to version 1.2.3
|
||||||
|
* Only require one email when validating GPG key (#2266, #2467, #2663) (#2788)
|
||||||
|
* Fix order of comments (#2835) (#2839)
|
||||||
|
|
||||||
|
[1.2.0]
|
||||||
|
* Update to version 1.3.0
|
||||||
|
|
||||||
|
[1.3.0]
|
||||||
|
* Update to version 1.3.1
|
||||||
|
* Add documentationUrl
|
||||||
|
* Sanitize logs for mirror sync (#3057, #3082) (#3078)
|
||||||
|
* Fix missing branch in release bug (#3108) (#3117)
|
||||||
|
* Fix repo indexer and submodule bug (#3107) (#3110)
|
||||||
|
* Fix legacy URL redirects (#3100) (#3106)
|
||||||
|
* Fix redis session failed (#3086) (#3089)
|
||||||
|
* Fix issue list branch link broken (#3061) (#3070)
|
||||||
|
* Fix missing password length check when change password (#3039) (#3071)
|
||||||
|
|
||||||
|
[1.3.1]
|
||||||
|
* Update Gitea to 1.3.2
|
||||||
|
* Fix run web with -p push failed (#3154) (#3179)
|
||||||
|
* Fix source download link when no code unit allowed (#3166) (#3169)
|
||||||
|
* Allow adding collaborators with (fullname) (#3103) (#3168)
|
||||||
|
* Fix repo links (#3093) (#3163)
|
||||||
|
* Fix Uninitialized variable in ParsePatch (#3156) (#3162)
|
||||||
|
* Fix migration order v1.3 (#3157)
|
||||||
|
* Fix avatar URLs (#3069) (#3143)
|
||||||
|
|
||||||
|
[1.4.0]
|
||||||
|
* Fix email sending (use SMTPS)
|
||||||
|
|
||||||
|
[1.4.1]
|
||||||
|
* Update Gitea to 1.3.3
|
||||||
|
* Security fixes
|
||||||
|
* Fix escaping changed title in comments (#3530) (#3535)
|
||||||
|
* Escape search query display (#3486) (#3489)
|
||||||
|
* Bug fixes
|
||||||
|
* Fix repo-transfer-and-team-repo-count bug (#3241) (#3244)
|
||||||
|
* Open external tracker in blank window, consistently with wiki (#3227) (#3228)
|
||||||
|
* Change SSL Mode from checkbox to string in admin page (#3208) (#3211)
|
||||||
|
|
||||||
|
[1.5.0]
|
||||||
|
* Update Gitea to 1.4.0
|
||||||
|
|
||||||
|
[1.5.1]
|
||||||
|
* Update Gitea to 1.4.1
|
||||||
|
* Add “error” as reserved username (#3882) (#3886)
|
||||||
|
* Do not allow inactive users to access repositories using private key (#3887) (#3889)
|
||||||
|
* Fix path cleanup in file editor, when initilizing new repository and LFS oids (#3871) (#3873)
|
||||||
|
* Remove unnecessary allowed safe HTML (#3778) (#3779)
|
||||||
|
* Correctly check http git access rights for reverse proxy authorized users (#3721) (#3743)
|
||||||
|
* Fix to use only needed columns from tables to get repository git paths (#3870) (#3883)
|
||||||
|
* Fix GPG expire time display when time is zero (#3584) (#3884)
|
||||||
|
* Fix to update only issue last update time when adding a comment (#3855) (#3860)
|
||||||
|
* Fix repository star count after deleting user (#3781) (#3783)
|
||||||
|
* Use the active branch for the code tab (#3720) (#3776)
|
||||||
|
* Set default branch name on first push (#3715) (#3723)
|
||||||
|
* Show clipboard button if disable HTTP of git protocol (#3773) (#3774)
|
||||||
|
|
||||||
|
[1.5.2]
|
||||||
|
* Update Gitea to 1.4.2
|
||||||
|
* Adjust z-index for floating labels (#3939) (#3950)
|
||||||
|
* Add missing token validation on application settings page (#3976) #3978
|
||||||
|
* Webhook and hook_task clean up (#4006)
|
||||||
|
* Fix webhook bug of response info is not displayed in UI (#4023)
|
||||||
|
* Fix writer cannot read bare repo guide (#4033) (#4039)
|
||||||
|
* Don't force due date to current time (#3830) (#4057)
|
||||||
|
* Fix wiki redirects (#3919) (#4065)
|
||||||
|
* Fix attachment ENABLED (#4064) (#4066)
|
||||||
|
* Added deletion of an empty line at the end of file (#4054) (#4074)
|
||||||
|
* Use ResolveReference instead of path.Join (#4073)
|
||||||
|
* Fix #4081 Check for leading / in base before removing it (#4083)
|
||||||
|
* Respository's home page not updated after first push (#4075)
|
||||||
|
|
||||||
|
[1.5.2-1]
|
||||||
|
* Rebuild Gitea package because of https://github.com/go-gitea/gitea/issues/4167
|
||||||
|
* Adjust z-index for floating labels (#3939) (#3950)
|
||||||
|
* Add missing token validation on application settings page (#3976) #3978
|
||||||
|
* Webhook and hook_task clean up (#4006)
|
||||||
|
* Fix webhook bug of response info is not displayed in UI (#4023)
|
||||||
|
* Fix writer cannot read bare repo guide (#4033) (#4039)
|
||||||
|
* Don't force due date to current time (#3830) (#4057)
|
||||||
|
* Fix wiki redirects (#3919) (#4065)
|
||||||
|
* Fix attachment ENABLED (#4064) (#4066)
|
||||||
|
* Added deletion of an empty line at the end of file (#4054) (#4074)
|
||||||
|
* Use ResolveReference instead of path.Join (#4073)
|
||||||
|
* Fix #4081 Check for leading / in base before removing it (#4083)
|
||||||
|
* Respository's home page not updated after first push (#4075)
|
||||||
|
|
||||||
|
[1.5.3]
|
||||||
|
* Update Gitea to 1.4.3
|
||||||
|
* SECURITY
|
||||||
|
* HTML-escape plain-text READMEs (#4192) (#4214)
|
||||||
|
* Fix open redirect vulnerability on login screen (#4312) (#4312)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix broken monitoring page when running processes are shown (#4203) (#4208)
|
||||||
|
* Fix delete comment bug (#4216) (#4228)
|
||||||
|
* Delete reactions added to issues and comments when deleting repository (#4232) (#4237)
|
||||||
|
* Fix wiki URL encoding bug (#4091) (#4254)
|
||||||
|
* Fix code tab link when viewing tags (#3908) (#4263)
|
||||||
|
* Fix webhook type conflation (#4285) (#4285)
|
||||||
|
|
||||||
|
[1.5.4]
|
||||||
|
* Allow customization using gitea's custom data directory
|
||||||
|
|
||||||
|
[1.6.0]
|
||||||
|
* Update Gitea to 1.5.0
|
||||||
|
* Security
|
||||||
|
* Check that repositories can only be migrated to own user or organizations (#4366) (#4370)
|
||||||
|
* Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
|
||||||
|
* Do not allow to reuse TOTP passcode (#3878)
|
||||||
|
* Features
|
||||||
|
* Add cli commands to regen hooks & keys (#3979)
|
||||||
|
* Add support for FIDO U2F (#3971)
|
||||||
|
* Added user language setting (#3875)
|
||||||
|
* Add topic support (#3711)
|
||||||
|
* Multiple assignees (#3705)
|
||||||
|
* Add protected branch whitelists for merging (#3689)
|
||||||
|
* Global code search support (#3664)
|
||||||
|
* Add label descriptions (#3662)
|
||||||
|
* Add issue search via API (#3612)
|
||||||
|
* Add repository setting to enable/disable health checks (#3607)
|
||||||
|
* Emoji Autocomplete (#3433)
|
||||||
|
* Implements generator cli for secrets (#3531)
|
||||||
|
|
||||||
|
[1.6.1]
|
||||||
|
* Update Gitea to 1.5.1
|
||||||
|
* Security
|
||||||
|
* Don't disclose emails of all users when sending out emails (#4784)
|
||||||
|
* Improve URL validation for external wiki and external issues (#4710) (#4740)
|
||||||
|
* Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) (#4707)
|
||||||
|
* Bugfixes
|
||||||
|
* Fix missing release title in webhook (#4783) (#4800)
|
||||||
|
* Make sure to reset commit count in the cache on mirror syncing (#4770)
|
||||||
|
* Fixed bug where team with admin privelege type doesn't get any unit (#4759)
|
||||||
|
* Fix failure on creating pull request with assignees (#4583) (#4727)
|
||||||
|
* Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686)
|
||||||
|
|
||||||
|
[1.7.0]
|
||||||
|
* Update base image
|
||||||
|
|
||||||
|
[1.7.1]
|
||||||
|
* Update Gitea to 1.5.2
|
||||||
|
|
||||||
|
[1.7.2]
|
||||||
|
* Update Gitea to 1.5.3
|
||||||
|
* Security
|
||||||
|
* Fix remote command execution vulnerability in upstream library (#5177) (#5196)
|
||||||
|
|
||||||
|
[1.8.0]
|
||||||
|
* Update Gitea to 1.6.0
|
||||||
|
|
||||||
|
[1.8.1]
|
||||||
|
* Update Gitea to 1.6.1
|
||||||
|
|
||||||
|
[1.8.2]
|
||||||
|
* Update Gitea to 1.6.2
|
||||||
|
* SECURITY
|
||||||
|
* Sanitize uploaded file names (#5571) (#5573)
|
||||||
|
* HTMLEncode user added text (#5570) (#5575)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix indexer reindex bug when gitea restart (#5563) (#5564)
|
||||||
|
* Fix bug when a read perm user to edit his issue (#5516) (#5534)
|
||||||
|
* Detect force push failure on deletion of protected branches (#5522) (#5531)
|
||||||
|
* Fix forgot deletion of notification when delete repository (#5506) (#5514)
|
||||||
|
* Fix undeleted content when deleting user (#5429) (#5509)
|
||||||
|
* Fix empty wiki (#5504) (#5508)
|
||||||
|
|
||||||
|
[1.8.3]
|
||||||
|
* Update Gitea to 1.6.3
|
||||||
|
* SECURITY: Prevent DeleteFilePost doing arbitrary deletion (#5631)
|
||||||
|
* BUGFIX: Fix wrong text getting saved on editing second comment on an issue (#5608)
|
||||||
|
|
||||||
|
[1.8.4]
|
||||||
|
* Update Gitea to 1.6.4
|
||||||
|
* Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685)
|
||||||
|
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5703)
|
||||||
|
* Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715)
|
||||||
|
|
||||||
|
[1.9.0]
|
||||||
|
* Update Gitea to 1.7.0
|
||||||
|
|
||||||
|
[1.9.1]
|
||||||
|
* Update Gitea to 1.7.1
|
||||||
|
* [Changelog](https://github.com/go-gitea/gitea/releases/tag/v1.7.1)
|
||||||
|
* Disable redirect for i18n (#5910) (#5916)
|
||||||
|
* Only allow local login if password is non-empty (#5906) (#5908)
|
||||||
|
* Fix go-get URL generation (#5905) (#5907)
|
||||||
|
* Fix TLS errors when using acme/autocert for local connections (#5820) (#5826)
|
||||||
|
* Request for public keys only if LDAP attribute is set (#5816) (#5819)
|
||||||
|
* Fix delete correct temp directory (#5840) (#5839)
|
||||||
|
* Fix an error while adding a dependency via UI (#5862) (#5876)
|
||||||
|
* Fix null pointer in attempt to Sudo if not logged in (#5872) (#5884)
|
||||||
|
* When creating new repository fsck option should be enabled (#5817) (#5885)
|
||||||
|
* Prevent nil dereference in mailIssueCommentToParticipants (#5891) (#5895) (#5894)
|
||||||
|
* Fix bug when read public repo lfs file (#5913) (#5912)
|
||||||
|
* Respect value of REQUIRE_SIGNIN_VIEW (#5901) (#5915)
|
||||||
|
* Fix compare button on upstream repo leading to 404 (#5877) (#5914)
|
||||||
|
|
||||||
|
[1.9.2]
|
||||||
|
* Update Gitea to 1.7.2
|
||||||
|
* Remove all CommitStatus when a repo is deleted (#5940) (#5941)
|
||||||
|
* Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944)
|
||||||
|
* Silence console logger in gitea serv (#5887) (#5943)
|
||||||
|
* Handle milestone webhook events for issues and PR (#5947) (#5955)
|
||||||
|
* Show user who created the repository instead of the organization in action feed (#5948) (#5956)
|
||||||
|
* Fix ssh deploy and user key constraints (#1357) (#5939) (#5966)
|
||||||
|
* Fix bug when deleting a linked account will removed all (#5989) (#5990)
|
||||||
|
* Fix empty ssh key importing in ldap (#5984) (#6009)
|
||||||
|
* Fix metrics auth token detection (#6006) (#6017)
|
||||||
|
* Create repository on organisation by default on its dashboard (#6026) (#6048)
|
||||||
|
* Make sure labels are actually returned in API (#6053) (#6059)
|
||||||
|
* Switch to more recent build of xgo (#6070) (#6072)
|
||||||
|
* In basic auth check for tokens before call UserSignIn (#5725) (#6083)
|
||||||
|
|
||||||
|
[1.9.3]
|
||||||
|
* Update Gitea to 1.7.3
|
||||||
|
* Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197)
|
||||||
|
* Load Issue attributes for API /repos/{owner}/{repo}/issues/{index} (#6122) (#6185)
|
||||||
|
* Fix bug whereby user could change private repository to public when force private enabled. (#6156) (#6165)
|
||||||
|
* Fix bug when update owner team then visit team's repo return 404 (#6119) (#6166)
|
||||||
|
* Fix heatmap and repository menu display in Internet Explorer 9+ (#6117) (#6137)
|
||||||
|
* Fix prohibit login check on authorization (#6106) (#6115)
|
||||||
|
* Fix LDAP protocol error regression by moving to ldap.v3 (#6105) (#6107)
|
||||||
|
* Fix deadlock in webhook PullRequest (#6102) (#6104)
|
||||||
|
* Fix redirect loop when password change is required and Gitea is installed as a suburl (#5965) (#6101)
|
||||||
|
* Fix compare button regression (#5929) (#6098)
|
||||||
|
* Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097)
|
||||||
|
|
||||||
|
[1.9.4]
|
||||||
|
* Update Gitea to 1.7.4
|
||||||
|
* Fix potential XSS vulnerability in repository description. (#6306) (#6308)
|
||||||
|
* Fix wrong release commit id (#6224) (#6300)
|
||||||
|
* Fix panic on empty signed commits (#6292) (#6300)
|
||||||
|
* Fix organization dropdown not being scrollable when using mouse wheel (#5988) (#6246)
|
||||||
|
* Fix displaying dashboard even if required to change password (#6214) (#6215)
|
||||||
|
|
1645
CHANGELOG.md
1645
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
|
@ -4,16 +4,14 @@
|
||||||
"author": "Gitea developers",
|
"author": "Gitea developers",
|
||||||
"description": "file://DESCRIPTION.md",
|
"description": "file://DESCRIPTION.md",
|
||||||
"tagline": "A painless self-hosted Git Service",
|
"tagline": "A painless self-hosted Git Service",
|
||||||
"version": "1.33.3",
|
"version": "1.9.4",
|
||||||
"upstreamVersion": "1.22.3",
|
"healthCheckPath": "/healthcheck",
|
||||||
"healthCheckPath": "/explore",
|
|
||||||
"httpPort": 3000,
|
"httpPort": 3000,
|
||||||
"memoryLimit": 536870912,
|
|
||||||
"addons": {
|
"addons": {
|
||||||
"mysql": { },
|
"mysql": { },
|
||||||
"sendmail": { "supportsDisplayName": true },
|
"sendmail": { },
|
||||||
"localstorage": { },
|
"localstorage": { },
|
||||||
"oidc": { "loginRedirectUri": "/user/oauth2/cloudron/callback" }
|
"ldap": { }
|
||||||
},
|
},
|
||||||
"tcpPorts": {
|
"tcpPorts": {
|
||||||
"SSH_PORT": {
|
"SSH_PORT": {
|
||||||
|
@ -22,22 +20,20 @@
|
||||||
"defaultValue": 29418
|
"defaultValue": 29418
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"manifestVersion": 2,
|
"manifestVersion": 1,
|
||||||
"website": "https://gitea.io",
|
"website": "https://gitea.io",
|
||||||
"contactEmail": "apps@cloudron.io",
|
"contactEmail": "apps@cloudron.io",
|
||||||
"icon": "file://logo.png",
|
"icon": "file://logo.png",
|
||||||
"optionalSso": true,
|
|
||||||
"mediaLinks": [
|
"mediaLinks": [
|
||||||
"https://screenshots.cloudron.io/io.gitea.cloudronapp/1.png",
|
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/1.png",
|
||||||
"https://screenshots.cloudron.io/io.gitea.cloudronapp/2.png",
|
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/2.png",
|
||||||
"https://screenshots.cloudron.io/io.gitea.cloudronapp/3.png",
|
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/3.png",
|
||||||
"https://screenshots.cloudron.io/io.gitea.cloudronapp/4.png",
|
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/4.png",
|
||||||
"https://screenshots.cloudron.io/io.gitea.cloudronapp/5.png"
|
"https://s3.amazonaws.com/cloudron-app-screenshots/io.gitea.cloudronapp/f89a2ab8d49094c80589f69a2d60bef63b2dbb62/5.png"
|
||||||
],
|
],
|
||||||
"tags": [ "version control", "git", "code hosting", "development", "github", "bitbucket", "gitlab" ],
|
"tags": [ "version control", "git", "code hosting", "development" ],
|
||||||
"changelog": "file://CHANGELOG.md",
|
"changelog": "file://CHANGELOG",
|
||||||
"postInstallMessage": "file://POSTINSTALL.md",
|
"postInstallMessage": "file://POSTINSTALL.md",
|
||||||
"minBoxVersion": "7.5.1",
|
"minBoxVersion": "1.10.0",
|
||||||
"forumUrl": "https://forum.cloudron.io/category/19/gitea",
|
"documentationUrl": "https://cloudron.io/documentation/apps/gitea/"
|
||||||
"documentationUrl": "https://docs.cloudron.io/apps/gitea/"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
This app packages Gitea <upstream>1.7.4</upstream>
|
||||||
|
|
||||||
Gitea is a painless self-hosted Git service. It is similar to GitHub, Bitbucket or Gitlab.
|
Gitea is a painless self-hosted Git service. It is similar to GitHub, Bitbucket or Gitlab.
|
||||||
|
|
||||||
### Purpose
|
### Purpose
|
||||||
|
|
15
Dockerfile
15
Dockerfile
|
@ -1,10 +1,9 @@
|
||||||
FROM cloudron/base:4.2.0@sha256:46da2fffb36353ef714f97ae8e962bd2c212ca091108d768ba473078319a47f4
|
FROM cloudron/base:1.0.0@sha256:147a648a068a2e746644746bbfb42eb7a50d682437cead3c67c933c546357617
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y openssh-server git asciidoctor pandoc && \
|
apt-get install -y openssh-server git && \
|
||||||
rm -rf /etc/ssh_host_* && \
|
rm -rf /etc/ssh_host_* && \
|
||||||
rm -r /var/cache/apt /var/lib/apt/lists
|
rm -r /var/cache/apt /var/lib/apt/lists
|
||||||
RUN pip3 install jupyter
|
|
||||||
|
|
||||||
ADD supervisor/ /etc/supervisor/conf.d/
|
ADD supervisor/ /etc/supervisor/conf.d/
|
||||||
|
|
||||||
|
@ -14,15 +13,7 @@ RUN adduser --disabled-login --gecos 'Gitea' git
|
||||||
RUN passwd -d git
|
RUN passwd -d git
|
||||||
|
|
||||||
RUN mkdir -p /home/git/gitea
|
RUN mkdir -p /home/git/gitea
|
||||||
WORKDIR /home/git
|
RUN curl -L https://dl.gitea.io/gitea/1.7.4/gitea-1.7.4-linux-amd64 -o /home/git/gitea/gitea \
|
||||||
|
|
||||||
# for autosign feature
|
|
||||||
ENV GNUPGHOME="/app/data/gnupg"
|
|
||||||
|
|
||||||
# renovate: datasource=github-releases depName=go-gitea/gitea versioning=semver extractVersion=^v(?<version>.+)$
|
|
||||||
ARG GITEA_VERSION=1.22.3
|
|
||||||
|
|
||||||
RUN curl -L https://dl.gitea.io/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64 -o /home/git/gitea/gitea \
|
|
||||||
&& chmod +x /home/git/gitea/gitea
|
&& chmod +x /home/git/gitea/gitea
|
||||||
|
|
||||||
# setup config paths
|
# setup config paths
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
This app is pre-setup with an admin account. The initial credentials are:
|
This app integrates with the Cloudron SSO. Admins on Cloudron automatically
|
||||||
|
become admins on Gitea.
|
||||||
|
|
||||||
**Username**: root<br/>
|
If you want to disable Cloudron SSO, do the following:
|
||||||
**Password**: changeme<br/>
|
|
||||||
|
|
||||||
Please change the admin password immediately.
|
* Admin Panel -> Authentication -> 'cloudron' -> Uncheck 'This authentication is activated'
|
||||||
|
* Admin Panel -> Users -> Change Authentication Source to 'Local' and also give a password
|
||||||
|
|
||||||
|
You can edit `/app/data/app.ini` and add any custom configuration. See the
|
||||||
|
[configuration cheat sheet](https://docs.gitea.io/en-us/config-cheat-sheet)
|
||||||
|
for more information.
|
||||||
|
|
||||||
<sso>
|
|
||||||
Use the `Local` authentication source for logging in as admin.
|
|
||||||
</sso>
|
|
||||||
|
|
|
@ -48,31 +48,23 @@ ENABLED = true
|
||||||
; APP_DATA_PATH/attachments
|
; APP_DATA_PATH/attachments
|
||||||
PATH =
|
PATH =
|
||||||
|
|
||||||
[oauth2_client]
|
|
||||||
ENABLE_AUTO_REGISTRATION = true
|
|
||||||
USERNAME = sub
|
|
||||||
UPDATE_AVATAR = false
|
|
||||||
ACCOUNT_LINKING = auto
|
|
||||||
|
|
||||||
[mailer]
|
[mailer]
|
||||||
ENABLED = true
|
ENABLED = true
|
||||||
|
|
||||||
; those settings are protected and can't be modified
|
; those settings are protected and can't be modified
|
||||||
SMTP_ADDR = ##MAIL_SERVER
|
HOST = ##MAIL_SERVER:##MAIL_PORT
|
||||||
SMTP_PORT = ##MAIL_PORT
|
|
||||||
USER = ##MAIL_SMTP_USERNAME
|
USER = ##MAIL_SMTP_USERNAME
|
||||||
PASSWD = ##MAIL_SMTP_PASSWORD
|
PASSWD = ##MAIL_SMTP_PASSWORD
|
||||||
FROM = ##MAIL_FROM
|
FROM = ##MAIL_FROM
|
||||||
PROTOCOL = smtps
|
SKIP_VERIFY = true
|
||||||
FORCE_TRUST_SERVER_CERT = true
|
|
||||||
|
|
||||||
|
|
||||||
[security]
|
[security]
|
||||||
; those settings are protected and can't be modified
|
; those settings are protected and can't be modified
|
||||||
INSTALL_LOCK = true
|
INSTALL_LOCK = true
|
||||||
SECRET_KEY = ##SECRET_KEY
|
SECRET_KEY = ##SECRET_KEY
|
||||||
REVERSE_PROXY_LIMIT = 1
|
|
||||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
|
||||||
|
|
||||||
[service]
|
[service]
|
||||||
DISABLE_REGISTRATION = false
|
DISABLE_REGISTRATION = false
|
||||||
|
@ -103,32 +95,3 @@ PATH =
|
||||||
[indexer]
|
[indexer]
|
||||||
; this setting is protected and can't be modified
|
; this setting is protected and can't be modified
|
||||||
ISSUE_INDEXER_PATH = /app/data/appdata/indexers/issues.bleve
|
ISSUE_INDEXER_PATH = /app/data/appdata/indexers/issues.bleve
|
||||||
|
|
||||||
[session]
|
|
||||||
PROVIDER = file
|
|
||||||
PROVIDER_CONFIG = /run/gitea/sessions
|
|
||||||
COOKIE_SECURE = true
|
|
||||||
COOKIE_NAME = cloudron_gitea
|
|
||||||
GC_INTERVAL_TIME = 2592000
|
|
||||||
|
|
||||||
[markup.asciidoc]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .adoc,.asciidoc
|
|
||||||
RENDER_COMMAND = "asciidoctor -s -a showtitle --out-file=- -"
|
|
||||||
; Input is not a standard input but a file
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.restructuredtext]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .rst
|
|
||||||
RENDER_COMMAND = "timeout 30s pandoc +RTS -M512M -RTS -f rst"
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.jupyter]
|
|
||||||
ENABLED = true
|
|
||||||
FILE_EXTENSIONS = .ipynb
|
|
||||||
RENDER_COMMAND = "jupyter nbconvert --stdin --stdout --to html --template basic"
|
|
||||||
IS_INPUT_FILE = false
|
|
||||||
|
|
||||||
[markup.sanitizer.jupyter.img]
|
|
||||||
ALLOW_DATA_URI_IMAGES = true
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
||||||
"extends": ["local>devops/renovator//default.renovate.json5"]
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@
|
||||||
Port 29418
|
Port 29418
|
||||||
# Use these options to restrict which interfaces/protocols sshd will bind to
|
# Use these options to restrict which interfaces/protocols sshd will bind to
|
||||||
ListenAddress 0.0.0.0
|
ListenAddress 0.0.0.0
|
||||||
ListenAddress ::
|
|
||||||
Protocol 2
|
Protocol 2
|
||||||
# HostKeys for protocol version 2
|
# HostKeys for protocol version 2
|
||||||
HostKey /app/data/sshd/ssh_host_rsa_key
|
HostKey /app/data/sshd/ssh_host_rsa_key
|
||||||
|
|
94
start.sh
94
start.sh
|
@ -2,49 +2,29 @@
|
||||||
|
|
||||||
set -eu -o pipefail
|
set -eu -o pipefail
|
||||||
|
|
||||||
mkdir -p /run/gitea/tmp/uploads /run/sshd /run/gitea/sessions
|
mkdir -p /run/gitea/tmp/uploads /run/sshd
|
||||||
|
|
||||||
setup_oidc_source() {
|
setup_ldap_source() {
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
echo "==> Setup OIDC source"
|
# Wait for gitea to finish db setup, before we insert ldap source in db
|
||||||
|
while ! curl --fail http://localhost:3000/healthcheck; do
|
||||||
now=$(date +%s)
|
echo "Waiting for gitea to come up"
|
||||||
mysql -u"${CLOUDRON_MYSQL_USERNAME}" -p"${CLOUDRON_MYSQL_PASSWORD}" -h mysql --database="${CLOUDRON_MYSQL_DATABASE}" -e \
|
|
||||||
"REPLACE INTO login_source (id, type, name, is_active, cfg, created_unix, updated_unix) VALUES (1,6,'cloudron', 1,'{\"Provider\":\"openidConnect\",\"ClientID\":\"${CLOUDRON_OIDC_CLIENT_ID}\",\"ClientSecret\":\"${CLOUDRON_OIDC_CLIENT_SECRET}\",\"OpenIDConnectAutoDiscoveryURL\":\"${CLOUDRON_OIDC_ISSUER}/.well-known/openid-configuration\",\"CustomURLMapping\":null,\"IconURL\":\"\",\"Scopes\":[\"openid email profile\"],\"RequiredClaimName\":\"\",\"RequiredClaimValue\":\"\",\"GroupClaimName\":\"\",\"AdminGroup\":\"\",\"GroupTeamMap\":\"\",\"GroupTeamMapRemoval\":false,\"RestrictedGroup\":\"\"}','${now}','${now}')"
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_root_user() {
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
if sudo -H -u git /home/git/gitea/gitea admin user create --username root --password changeme --email admin@cloudron.local --admin -c /run/gitea/app.ini; then
|
|
||||||
echo "==> root user added"
|
|
||||||
else
|
|
||||||
echo "==> Failed to add root user"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_auth() {
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
# Wait for gitea to finish db setup, before we do any db operations
|
|
||||||
while ! curl --fail http://localhost:3000/explore; do
|
|
||||||
echo "==> Waiting for gitea to come up"
|
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "==> Gitea is up, setting up auth"
|
now=$(date +%s)
|
||||||
|
|
||||||
if [[ -n "${CLOUDRON_OIDC_ISSUER:-}" ]]; then
|
# Get the existing LDAP source status. This allows the user to disable LDAP
|
||||||
setup_oidc_source
|
ldap_status=$(mysql -u"${MYSQL_USERNAME}" -p"${MYSQL_PASSWORD}" -h mysql --database="${MYSQL_DATABASE}" -N -B -e "select is_actived from login_source WHERE name='cloudron';")
|
||||||
fi
|
[[ -z "${ldap_status}" ]] && ldap_status="1"
|
||||||
|
|
||||||
user_count=$(mysql -u"${CLOUDRON_MYSQL_USERNAME}" -p"${CLOUDRON_MYSQL_PASSWORD}" -h mysql --database="${CLOUDRON_MYSQL_DATABASE}" -N -B -e "SELECT count(*) FROM user")
|
if mysql -u"${MYSQL_USERNAME}" -p"${MYSQL_PASSWORD}" -h mysql --database="${MYSQL_DATABASE}" \
|
||||||
# be careful, not to create root user for existing LDAP based installs
|
-e "REPLACE INTO login_source (id, type, name, is_actived, cfg, created_unix, updated_unix) VALUES (1,2,'cloudron',${ldap_status},'{\"Name\":\"cloudron\",\"Host\":\"${LDAP_SERVER}\",\"Port\":${LDAP_PORT},\"UseSSL\":false,\"SkipVerify\":true,\"BindDN\":\"${LDAP_BIND_DN}\",\"BindPassword\":\"${LDAP_BIND_PASSWORD}\",\"UserBase\":\"${LDAP_USERS_BASE_DN}\",\"AttributeUsername\":\"username\",\"AttributeName\":\"displayname\",\"AttributeSurname\":\"\",\"AttributeMail\":\"mail\",\"Filter\":\"(\\\\u007C(mail=%[1]s)(username=%[1]s))\",\"AdminFilter\":\"(memberof=cn=admins,${LDAP_GROUPS_BASE_DN})\"}','${now}','${now}');"; then
|
||||||
if [[ "${user_count}" == "0" ]]; then
|
echo "LDAP Authentication was setup with status ${ldap_status}"
|
||||||
echo "==> Setting up root user for first run"
|
else
|
||||||
setup_root_user
|
echo "Failed to setup LDAP authentication"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,26 +52,30 @@ chmod 0644 /app/data/sshd/*.pub
|
||||||
|
|
||||||
sed -e "s/^Port .*/Port ${SSH_PORT}/" /etc/ssh/sshd_config > /run/gitea/sshd_config
|
sed -e "s/^Port .*/Port ${SSH_PORT}/" /etc/ssh/sshd_config > /run/gitea/sshd_config
|
||||||
|
|
||||||
if [[ ! -f /app/data/app.ini ]]; then
|
cp /home/git/app.ini.template "/run/gitea/app.ini"
|
||||||
echo -e "; Add customizations here - https://docs.gitea.io/en-us/config-cheat-sheet/" > /app/data/app.ini
|
|
||||||
|
|
||||||
echo "==> Generating new SECRET_KEY"
|
# create default user config file
|
||||||
|
if ! [ -f /app/data/app.ini ]; then
|
||||||
|
cp /home/git/app.ini.template /app/data/app.ini
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(crudini --get /app/data/app.ini security SECRET_KEY)" == "##SECRET_KEY" ]; then
|
||||||
|
echo "Generating new SECRET_KEY"
|
||||||
crudini --set "/app/data/app.ini" security SECRET_KEY $(pwgen -1 -s)
|
crudini --set "/app/data/app.ini" security SECRET_KEY $(pwgen -1 -s)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# merge user config file
|
# merge user config file
|
||||||
cp /home/git/app.ini.template "/run/gitea/app.ini"
|
|
||||||
crudini --merge "/run/gitea/app.ini" < "/app/data/app.ini"
|
crudini --merge "/run/gitea/app.ini" < "/app/data/app.ini"
|
||||||
|
|
||||||
# override important values
|
# override important values
|
||||||
crudini --set "/run/gitea/app.ini" database DB_TYPE mysql
|
crudini --set "/run/gitea/app.ini" database DB_TYPE mysql
|
||||||
crudini --set "/run/gitea/app.ini" database HOST "${CLOUDRON_MYSQL_HOST}:${CLOUDRON_MYSQL_PORT}"
|
crudini --set "/run/gitea/app.ini" database HOST "${MYSQL_HOST}:${MYSQL_PORT}"
|
||||||
crudini --set "/run/gitea/app.ini" database NAME "${CLOUDRON_MYSQL_DATABASE}"
|
crudini --set "/run/gitea/app.ini" database NAME "${MYSQL_DATABASE}"
|
||||||
crudini --set "/run/gitea/app.ini" database USER "${CLOUDRON_MYSQL_USERNAME}"
|
crudini --set "/run/gitea/app.ini" database USER "${MYSQL_USERNAME}"
|
||||||
crudini --set "/run/gitea/app.ini" database PASSWD "${CLOUDRON_MYSQL_PASSWORD}"
|
crudini --set "/run/gitea/app.ini" database PASSWD "${MYSQL_PASSWORD}"
|
||||||
crudini --set "/run/gitea/app.ini" database SSL_MODE "disable"
|
crudini --set "/run/gitea/app.ini" database SSL_MODE "disable"
|
||||||
crudini --set "/run/gitea/app.ini" server PROTOCOL "http"
|
crudini --set "/run/gitea/app.ini" server PROTOCOL "http"
|
||||||
crudini --set "/run/gitea/app.ini" server DOMAIN "${CLOUDRON_APP_DOMAIN}"
|
crudini --set "/run/gitea/app.ini" server DOMAIN "${APP_DOMAIN}"
|
||||||
crudini --set "/run/gitea/app.ini" server ROOT_URL "https://%(DOMAIN)s/"
|
crudini --set "/run/gitea/app.ini" server ROOT_URL "https://%(DOMAIN)s/"
|
||||||
crudini --set "/run/gitea/app.ini" server HTTP_ADDR ""
|
crudini --set "/run/gitea/app.ini" server HTTP_ADDR ""
|
||||||
crudini --set "/run/gitea/app.ini" server HTTP_PORT "3000"
|
crudini --set "/run/gitea/app.ini" server HTTP_PORT "3000"
|
||||||
|
@ -100,25 +84,21 @@ crudini --set "/run/gitea/app.ini" server SSH_PORT "${SSH_PORT}"
|
||||||
crudini --set "/run/gitea/app.ini" server APP_DATA_PATH "/app/data/appdata"
|
crudini --set "/run/gitea/app.ini" server APP_DATA_PATH "/app/data/appdata"
|
||||||
crudini --set "/run/gitea/app.ini" repository ROOT "/app/data/repository"
|
crudini --set "/run/gitea/app.ini" repository ROOT "/app/data/repository"
|
||||||
crudini --set "/run/gitea/app.ini" repository.upload TEMP_PATH "/run/gitea/tmp/uploads"
|
crudini --set "/run/gitea/app.ini" repository.upload TEMP_PATH "/run/gitea/tmp/uploads"
|
||||||
crudini --set "/run/gitea/app.ini" mailer SMTP_ADDR "${CLOUDRON_MAIL_SMTP_SERVER}"
|
crudini --set "/run/gitea/app.ini" mailer HOST "${MAIL_SMTP_SERVER}:${MAIL_SMTPS_PORT}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer SMTP_PORT "${CLOUDRON_MAIL_SMTPS_PORT}"
|
crudini --set "/run/gitea/app.ini" mailer USER "${MAIL_SMTP_USERNAME}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer PROTOCOL smtps
|
crudini --set "/run/gitea/app.ini" mailer PASSWD "${MAIL_SMTP_PASSWORD}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer USER "${CLOUDRON_MAIL_SMTP_USERNAME}"
|
crudini --set "/run/gitea/app.ini" mailer FROM "${MAIL_FROM}"
|
||||||
crudini --set "/run/gitea/app.ini" mailer PASSWD "${CLOUDRON_MAIL_SMTP_PASSWORD}"
|
crudini --set "/run/gitea/app.ini" mailer SKIP_VERIFY "true"
|
||||||
crudini --set "/run/gitea/app.ini" mailer FROM "${CLOUDRON_MAIL_FROM_DISPLAY_NAME:-Gitea} <${CLOUDRON_MAIL_FROM}>"
|
|
||||||
crudini --set "/run/gitea/app.ini" mailer FORCE_TRUST_SERVER_CERT "true"
|
|
||||||
crudini --set "/run/gitea/app.ini" security INSTALL_LOCK "true"
|
crudini --set "/run/gitea/app.ini" security INSTALL_LOCK "true"
|
||||||
crudini --set "/run/gitea/app.ini" security REVERSE_PROXY_LIMIT 1
|
|
||||||
crudini --set "/run/gitea/app.ini" security REVERSE_PROXY_TRUSTED_PROXIES "*"
|
|
||||||
crudini --set "/run/gitea/app.ini" log MODE "console"
|
crudini --set "/run/gitea/app.ini" log MODE "console"
|
||||||
crudini --set "/run/gitea/app.ini" log ROOT_PATH "/run/gitea"
|
crudini --set "/run/gitea/app.ini" log ROOT_PATH "/run/gitea"
|
||||||
crudini --set "/run/gitea/app.ini" indexer ISSUE_INDEXER_PATH "/app/data/appdata/indexers/issues.bleve"
|
crudini --set "/run/gitea/app.ini" indexer ISSUE_INDEXER_PATH "/app/data/appdata/indexers/issues.bleve"
|
||||||
|
|
||||||
echo "==> Creating dirs and changing permissions"
|
mkdir -p /app/data/repository /app/data/ssh /app/data/custom
|
||||||
mkdir -p /app/data/repository /app/data/ssh /app/data/custom /app/data/gnupg
|
|
||||||
chown -R git:git /app/data /run/gitea
|
chown -R git:git /app/data /run/gitea
|
||||||
|
|
||||||
# this expects app.ini to be available
|
( setup_ldap_source ) &
|
||||||
( setup_auth ) &
|
|
||||||
|
|
||||||
exec /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i Gitea
|
exec /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i Gitea
|
||||||
|
|
||||||
|
|
|
@ -8,3 +8,4 @@ stdout_logfile=/dev/stdout
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
stderr_logfile_maxbytes=0
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
ssh -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${SCRIPT_DIR}/id_ed25519 "$@"
|
ssh -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${SCRIPT_DIR}/id_rsa "$@"
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
|
||||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
|
||||||
QyNTUxOQAAACDECyFdxcmgOemNvs0wUhkgzfj9IS2OTG6bU5AXfNkXfgAAAJAoNQg/KDUI
|
|
||||||
PwAAAAtzc2gtZWQyNTUxOQAAACDECyFdxcmgOemNvs0wUhkgzfj9IS2OTG6bU5AXfNkXfg
|
|
||||||
AAAEC9nIZlzus9hn/b99E/cnSE2Vpycx0invItrrzgOX9qwMQLIV3FyaA56Y2+zTBSGSDN
|
|
||||||
+P0hLY5MbptTkBd82Rd+AAAADW5lYnVsb25AbHVuYXI=
|
|
||||||
-----END OPENSSH PRIVATE KEY-----
|
|
|
@ -1 +0,0 @@
|
||||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMQLIV3FyaA56Y2+zTBSGSDN+P0hLY5MbptTkBd82Rd+ nebulon@lunar
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEA14L+HdwPXRHC2A+fyRv1FTsRE/OPl0Z0KnEigzIIdA65CzTy
|
||||||
|
l3m3ATNFI1o/Ies7RW6rsr9UHuLLufNVg1NwIBdns8sPE4pSZSjfdPnznifIIs7y
|
||||||
|
wL/vn2D3JEhpA8EOasSy0c+z+6X23evsLB3D81y7ICsBc16Q147WZ6D+QMUP+A4b
|
||||||
|
wlmEcy0hAoPx/jnnPlRDVOK1ZnBvuAaHBkcBh+sA272BhB6Kv13MBu0wctDjKw5w
|
||||||
|
cNmgVWbzBBtK1L8BZVMDKmKWZ2PKP4GkkpnAvkD0+4sdARe148faV8HHigAKKNN7
|
||||||
|
vt+njs6nHuS4ksJL1E9cKGHdBJudJc3p24iI7QIDAQABAoIBABm5ojnQPek/KIIA
|
||||||
|
A3PPKYc6QMSf60EEgPNcA+GjRE0OQNpsnJSmS8kR5KvepvCWksGr/0Tb/9+b9POi
|
||||||
|
b0+40waRpKhakdckSMeYhGwDNihn2UUGbQXDI4hj27xyBE8VaXInPq063OIqInjF
|
||||||
|
I7D0cKKJLDEf0RGDdUi13TQLjK4QX78W/9S8d5ClznAVi4wUBb1urs7fAoVetn/i
|
||||||
|
PnlEj9KZHio4mCg28djTudAoWzjzUikRqKRYY5QNEJ13abVoLqIRSRHC1DzwpxVv
|
||||||
|
Y88l4hmm6IcmWGo0O9lpu5IJFvEmngfpmyaVbeLE0fhLPFWcEHARw37SThTZVQeY
|
||||||
|
Tx1816UCgYEA9j5dyNbFcC4YL9i9DQyut658bYziY2vsAvZNMMf249IJGbZOxlZK
|
||||||
|
ylB00zlbO/2uNh12Y9z6BN2hO2lER3O3SM75tCnvXR0+qG+xmfjLcRVczEkU10+r
|
||||||
|
8UxKBgg7Sf9uvfeONefEYPwiwzFoWgdaFSrR2sCmuoHPwfc9i+PSp+8CgYEA4Azq
|
||||||
|
DToKdv6VBWPlNXT6OW3+HUPeHF087Ve03+3orCckZ+d2DImEOvWdt+pDeGQJJcq+
|
||||||
|
o+SzZk9FjFOIiQehuA44OFrvcbag9YAlm1JQYYrRTdZEJz3iSucXCzJH/P5TrB84
|
||||||
|
BHvzgCklZzZ0IpEFxzMe8oNS6XfJmilh6I98YOMCgYBybOy7xUGeLW1D3p2LENen
|
||||||
|
t0dOyObyeFYF0lpwTpulphZgglz8wWCjvttqw/5nVCy+LNa09RyhYjPoHbSC13zW
|
||||||
|
MofKdqoqRMq3DqAjAn/XHqwuqc8rdnRZ/q9vOigC7NWTJRRKbFbPEps8xRrOqxfr
|
||||||
|
OiimVFul02ito6xP8yAStQKBgQDHbPdPup/h9wzx9U7p3Ct1vt/3cJddK+i1YeIP
|
||||||
|
iBYYVebjzXSYCDd4u3MdZxmTKYey6dnyy/ibUmgXVassPWzHBXEpSFflIaf3nY7b
|
||||||
|
x9LgX82ZuOSFAWJRRYyPXLwTBtW3WTplU2cUZotyaVfKBMfd3TToq9e7E/KQk9Eg
|
||||||
|
Tcdp/QKBgCyKD1gGU/H1bsQOuWHuFR1v7v82V1DLVjyn5kllej0tlfTLO/5uUsEE
|
||||||
|
SIjGHfTHxgpww9HN9BPyy8xdQMAc6p7UyvJAIyhg679AQBrMLLvhE5niaGu4jQOa
|
||||||
|
ZVY6nZUQNCwgxJwnUkFnOyXDYjzjyxZOCAWPxghYbS+IEl1GzhZU
|
||||||
|
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1 @@
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXgv4d3A9dEcLYD5/JG/UVOxET84+XRnQqcSKDMgh0DrkLNPKXebcBM0UjWj8h6ztFbquyv1Qe4su581WDU3AgF2ezyw8TilJlKN90+fOeJ8gizvLAv++fYPckSGkDwQ5qxLLRz7P7pfbd6+wsHcPzXLsgKwFzXpDXjtZnoP5AxQ/4DhvCWYRzLSECg/H+Oec+VENU4rVmcG+4BocGRwGH6wDbvYGEHoq/XcwG7TBy0OMrDnBw2aBVZvMEG0rUvwFlUwMqYpZnY8o/gaSSmcC+QPT7ix0BF7Xjx9pXwceKAAoo03u+36eOzqce5LiSwkvUT1woYd0Em50lzenbiIjt girish@beast
|
File diff suppressed because it is too large
Load Diff
|
@ -8,11 +8,18 @@
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"devDependencies": {
|
||||||
"chromedriver": "^129.0.2",
|
"ejs": "^2.3.4",
|
||||||
"expect.js": "^0.3.1",
|
"expect.js": "^0.3.1",
|
||||||
"mocha": "^10.7.3",
|
"mkdirp": "^0.5.1",
|
||||||
"selenium-webdriver": "^4.25.0",
|
"mocha": "^2.3.4",
|
||||||
"superagent": "^10.1.0"
|
"rimraf": "^2.4.4",
|
||||||
|
"superagent": "^1.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chromedriver": "^2.38.2",
|
||||||
|
"selenium-server-standalone-jar": "^3.3.1",
|
||||||
|
"selenium-webdriver": "^3.3.0",
|
||||||
|
"superagent": "^1.8.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
497
test/test.js
497
test/test.js
|
@ -1,225 +1,317 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/* jshint esversion: 8 */
|
/* jslint node:true */
|
||||||
/* global it, xit, describe, before, after, afterEach */
|
/* global it:false */
|
||||||
|
/* global xit:false */
|
||||||
|
/* global describe:false */
|
||||||
|
/* global before:false */
|
||||||
|
/* global after:false */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
require('chromedriver');
|
require('chromedriver');
|
||||||
|
|
||||||
const execSync = require('child_process').execSync,
|
var execSync = require('child_process').execSync,
|
||||||
|
ejs = require('ejs'),
|
||||||
expect = require('expect.js'),
|
expect = require('expect.js'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
|
mkdirp = require('mkdirp'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
|
rimraf = require('rimraf'),
|
||||||
superagent = require('superagent'),
|
superagent = require('superagent'),
|
||||||
{ Builder, By, until } = require('selenium-webdriver'),
|
webdriver = require('selenium-webdriver');
|
||||||
{ Options } = require('selenium-webdriver/chrome');
|
|
||||||
|
|
||||||
if (!process.env.USERNAME || !process.env.PASSWORD || !process.env.EMAIL) {
|
var by = require('selenium-webdriver').By,
|
||||||
console.log('USERNAME, PASSWORD and EMAIL env vars need to be set');
|
until = require('selenium-webdriver').until,
|
||||||
process.exit(1);
|
Builder = require('selenium-webdriver').Builder;
|
||||||
}
|
|
||||||
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||||
|
|
||||||
describe('Application life cycle test', function () {
|
describe('Application life cycle test', function () {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
var server, browser = new Builder().forBrowser('chrome').build();
|
||||||
|
var LOCATION = 'test';
|
||||||
|
var SSH_PORT = 29420;
|
||||||
|
var repodir = '/tmp/testrepo';
|
||||||
|
var app, reponame = 'testrepo';
|
||||||
|
var username = process.env.USERNAME;
|
||||||
|
var password = process.env.PASSWORD;
|
||||||
|
var TIMEOUT = parseInt(process.env.TIMEOUT, 10) || 5000;
|
||||||
|
var email, token;
|
||||||
|
|
||||||
const TIMEOUT = parseInt(process.env.TIMEOUT, 10) || 5000;
|
before(function (done) {
|
||||||
const EXEC_ARGS = { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' };
|
if (!process.env.USERNAME) return done(new Error('USERNAME env var not set'));
|
||||||
const LOCATION = process.env.LOCATION || 'test';
|
if (!process.env.PASSWORD) return done(new Error('PASSWORD env var not set'));
|
||||||
const SSH_PORT = 29420;
|
|
||||||
|
|
||||||
let app, browser;
|
var seleniumJar= require('selenium-server-standalone-jar');
|
||||||
let athenticated_by_oidc = false;
|
var SeleniumServer = require('selenium-webdriver/remote').SeleniumServer;
|
||||||
|
server = new SeleniumServer(seleniumJar.path, { port: 4444 });
|
||||||
|
server.start();
|
||||||
|
|
||||||
const repodir = '/tmp/testrepo';
|
done();
|
||||||
const reponame = 'testrepo';
|
|
||||||
|
|
||||||
const username = process.env.USERNAME;
|
|
||||||
const password = process.env.PASSWORD;
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
const chromeOptions = new Options().windowSize({ width: 1280, height: 1024 });
|
|
||||||
if (process.env.CI) chromeOptions.addArguments('no-sandbox', 'disable-dev-shm-usage', 'headless');
|
|
||||||
browser = new Builder().forBrowser('chrome').setChromeOptions(chromeOptions).build();
|
|
||||||
if (!fs.existsSync('./screenshots')) fs.mkdirSync('./screenshots');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function () {
|
after(function (done) {
|
||||||
browser.quit();
|
browser.quit();
|
||||||
fs.rmSync(repodir, { recursive: true, force: true });
|
server.stop();
|
||||||
|
rimraf.sync(repodir);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function () {
|
function waitForUrl(url, done) {
|
||||||
if (!process.env.CI || !app) return;
|
browser.wait(function () {
|
||||||
|
return browser.getCurrentUrl().then(function (currentUrl) {
|
||||||
const currentUrl = await browser.getCurrentUrl();
|
return currentUrl === url;
|
||||||
if (!currentUrl.includes(app.domain)) return;
|
});
|
||||||
expect(this.currentTest.title).to.be.a('string');
|
}, TIMEOUT).then(function () { done(); });
|
||||||
|
}
|
||||||
const screenshotData = await browser.takeScreenshot();
|
|
||||||
fs.writeFileSync(`./screenshots/${new Date().getTime()}-${this.currentTest.title.replaceAll(' ', '_')}.png`, screenshotData, 'base64');
|
|
||||||
});
|
|
||||||
|
|
||||||
function getAppInfo() {
|
function getAppInfo() {
|
||||||
const inspect = JSON.parse(execSync('cloudron inspect'));
|
var inspect = JSON.parse(execSync('cloudron inspect'));
|
||||||
app = inspect.apps.filter(function (a) { return a.location.indexOf(LOCATION) === 0; })[0];
|
|
||||||
|
app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0];
|
||||||
|
|
||||||
expect(app).to.be.an('object');
|
expect(app).to.be.an('object');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitForElement(elem) {
|
function setAvatarOld(done) {
|
||||||
await browser.wait(until.elementLocated(elem), TIMEOUT);
|
browser.get('https://' + app.fqdn + '/user/settings/avatar').then(function () {
|
||||||
await browser.wait(until.elementIsVisible(browser.findElement(elem)), TIMEOUT);
|
return browser.findElement(by.xpath('//input[@type="file" and @name="avatar"]')).sendKeys(path.resolve(__dirname, '../logo.png'));
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//button[contains(text(), "Update Avatar Setting")]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
if (app.manifest.version === '1.0.3') {
|
||||||
|
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(),"updated successfully")]')), TIMEOUT);
|
||||||
|
} else {
|
||||||
|
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(),"Your avatar setting has been updated.")]')), TIMEOUT);
|
||||||
|
}
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sleep(millis) {
|
function setAvatar(done) {
|
||||||
return new Promise(resolve => setTimeout(resolve, millis));
|
if (app.manifest.version === '1.5.4') return setAvatarOld(done);
|
||||||
|
|
||||||
|
browser.get('https://' + app.fqdn + '/user/settings').then(function () {
|
||||||
|
var button = browser.findElement(by.xpath('//label[contains(text(), "Use Custom Avatar")]'));
|
||||||
|
return browser.executeScript('arguments[0].scrollIntoView(false)', button);
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//label[contains(text(), "Use Custom Avatar")]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//input[@type="file" and @name="avatar"]')).sendKeys(path.resolve(__dirname, '../logo.png'));
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//button[contains(text(), "Update Avatar")]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(),"Your avatar has been updated.")]')), TIMEOUT);
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setAvatar() {
|
function checkAvatar(done) {
|
||||||
await browser.get('https://' + app.fqdn + '/user/settings');
|
return done();
|
||||||
|
superagent.get('https://' + app.fqdn + '/avatars/a3e6f3316fc1738e29d621e6a26e93d3').end(function (error, result) {
|
||||||
var button = await browser.findElement(By.xpath('//label[contains(text(), "Use Custom Avatar")]'));
|
expect(error).to.be(null);
|
||||||
await browser.executeScript('arguments[0].scrollIntoView(false)', button);
|
expect(result.statusCode).to.be(200);
|
||||||
await browser.findElement(By.xpath('//label[contains(text(), "Use Custom Avatar")]')).click();
|
done();
|
||||||
await browser.findElement(By.xpath('//input[@type="file" and @name="avatar"]')).sendKeys(path.resolve(__dirname, '../logo.png'));
|
});
|
||||||
await browser.findElement(By.xpath('//button[contains(text(), "Update Avatar")]')).click();
|
|
||||||
await browser.wait(until.elementLocated(By.xpath('//p[contains(text(),"Your avatar has been updated.")]')), TIMEOUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkAvatar() {
|
function editFile(done) {
|
||||||
await browser.get(`https://${app.fqdn}/${username}`);
|
browser.get('https://' + app.fqdn + '/' + username + '/' + reponame + '/_edit/master/newfile').then(function () {
|
||||||
|
var cm = browser.findElement(by.xpath('//div[contains(@class,"CodeMirror")]'));
|
||||||
const avatarSrc = await browser.findElement(By.xpath('//div[@id="profile-avatar"]/a/img')).getAttribute('src');
|
var text = 'yo';
|
||||||
|
return browser.executeScript('arguments[0].CodeMirror.setValue("' + text + '");', cm);
|
||||||
const response = await superagent.get(avatarSrc);
|
}).then(function () {
|
||||||
expect(response.statusCode).to.equal(200);
|
return browser.findElement(by.xpath('//input[@name="commit_summary"]')).sendKeys('Dummy edit');
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//button[contains(text(), "Commit Changes")]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
waitForUrl('https://' + app.fqdn + '/' + username + '/' + reponame + '/src/branch/master/newfile', done);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login(username, password) {
|
function login(done) {
|
||||||
await browser.get('https://' + app.fqdn + '/user/login');
|
browser.get('https://' + app.fqdn + '/user/login').then(function () {
|
||||||
|
return browser.findElement(by.id('user_name')).sendKeys(username);
|
||||||
await browser.findElement(By.id('user_name')).sendKeys(username);
|
}).then(function () {
|
||||||
await browser.findElement(By.id('password')).sendKeys(password);
|
return browser.findElement(by.id('password')).sendKeys(password);
|
||||||
await browser.findElement(By.xpath('//form[@action="/user/login"]//button')).click();
|
}).then(function () {
|
||||||
await browser.wait(until.elementLocated(By.xpath('//img[contains(@class, "avatar")]')), TIMEOUT);
|
return browser.findElement(by.tagName('form')).submit();
|
||||||
|
}).then(function () {
|
||||||
|
return browser.wait(until.elementLocated(by.linkText('Dashboard')), TIMEOUT);
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function adminLogin() {
|
function addPublicKey(done) {
|
||||||
await login('root', 'changeme');
|
var publicKey = fs.readFileSync(__dirname + '/id_rsa.pub', 'utf8');
|
||||||
|
|
||||||
|
const sshPage = 'https://' + app.fqdn + '/user/settings/keys';
|
||||||
|
|
||||||
|
browser.get(sshPage).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//div[text()="Add Key"]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.id('ssh-key-title')).sendKeys('testkey');
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.id('ssh-key-content')).sendKeys(publicKey.trim()); // #3480
|
||||||
|
}).then(function () {
|
||||||
|
var button = browser.findElement(by.xpath('//button[contains(text(), "Add Key")]'));
|
||||||
|
return browser.executeScript('arguments[0].scrollIntoView(false)', button);
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//button[contains(text(), "Add Key")]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
if (app.manifest.version === '1.0.3') {
|
||||||
|
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(), "added successfully!")]')), TIMEOUT);
|
||||||
|
} else {
|
||||||
|
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(), "has been added.")]')), TIMEOUT);
|
||||||
|
}
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loginOIDC(username, password) {
|
function createRepo(done) {
|
||||||
browser.manage().deleteAllCookies();
|
var getRepoPage;
|
||||||
await browser.get(`https://${app.fqdn}/user/login`);
|
if (app.manifest.version === '1.0.3') {
|
||||||
await browser.sleep(2000);
|
getRepoPage = browser.get('https://' + app.fqdn).then(function () {
|
||||||
|
return browser.findElement(by.linkText('New Repository')).click();
|
||||||
|
}).then(function () {
|
||||||
await browser.findElement(By.xpath('//a[contains(@class, "openidConnect") and contains(., "Sign in with cloudron")]')).click();
|
return browser.wait(until.elementLocated(by.xpath('//*[contains(text(), "New Repository")]')), TIMEOUT);
|
||||||
await browser.sleep(2000);
|
});
|
||||||
|
} else {
|
||||||
if (!athenticated_by_oidc) {
|
getRepoPage = browser.get('https://' + app.fqdn + '/repo/create');
|
||||||
await waitForElement(By.xpath('//input[@name="username"]'));
|
|
||||||
await browser.findElement(By.xpath('//input[@name="username"]')).sendKeys(username);
|
|
||||||
await browser.findElement(By.xpath('//input[@name="password"]')).sendKeys(password);
|
|
||||||
await browser.sleep(2000);
|
|
||||||
await browser.findElement(By.id('loginSubmitButton')).click();
|
|
||||||
await browser.sleep(2000);
|
|
||||||
|
|
||||||
athenticated_by_oidc = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitForElement(By.xpath('//img[contains(@class, "avatar")]'));
|
getRepoPage.then(function () {
|
||||||
|
return browser.findElement(by.id('repo_name')).sendKeys(reponame);
|
||||||
|
}).then(function () {
|
||||||
|
var button = browser.findElement(by.xpath('//button[contains(text(), "Create Repository")]'));
|
||||||
|
return browser.executeScript('arguments[0].scrollIntoView(true)', button);
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.id('auto-init')).click();
|
||||||
|
}).then(function () {
|
||||||
|
return browser.findElement(by.xpath('//button[contains(text(), "Create Repository")]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
browser.wait(function () {
|
||||||
|
return browser.getCurrentUrl().then(function (url) {
|
||||||
|
return url === 'https://' + app.fqdn + '/' + username + '/' + reponame;
|
||||||
|
});
|
||||||
|
}, TIMEOUT);
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function logout() {
|
function checkCloneUrl(done) {
|
||||||
await browser.get('https://' + app.fqdn);
|
browser.get('https://' + app.fqdn + '/' + username + '/' + reponame).then(function () {
|
||||||
|
return browser.findElement(by.id('repo-clone-ssh')).click();
|
||||||
await browser.findElement(By.xpath('//img[contains(@class, "avatar")]')).click();
|
}).then(function () {
|
||||||
await sleep(2000);
|
return browser.findElement(by.id('repo-clone-url')).getAttribute('value');
|
||||||
await browser.findElement(By.xpath('//a[@data-url="/user/logout"]')).click();
|
}).then(function (cloneUrl) {
|
||||||
await sleep(2000);
|
expect(cloneUrl).to.be(`ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame}.git`);
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addPublicKey() {
|
function cloneRepo(done) {
|
||||||
const publicKey = fs.readFileSync(__dirname + '/id_ed25519.pub', 'utf8');
|
rimraf.sync(repodir);
|
||||||
execSync(`chmod g-rw,o-rw ${__dirname}/id_ed25519`); // ssh will complain about perms later
|
|
||||||
|
|
||||||
await browser.get('https://' + app.fqdn + '/user/settings/keys');
|
|
||||||
|
|
||||||
await browser.wait(until.elementLocated(By.id('add-ssh-button')), TIMEOUT);
|
|
||||||
await browser.findElement(By.id('add-ssh-button')).click();
|
|
||||||
await browser.findElement(By.id('ssh-key-title')).sendKeys('testkey');
|
|
||||||
await browser.findElement(By.id('ssh-key-content')).sendKeys(publicKey.trim()); // #3480
|
|
||||||
var button = browser.findElement(By.xpath('//button[contains(text(), "Add Key")]'));
|
|
||||||
await browser.executeScript('arguments[0].scrollIntoView(false)', button);
|
|
||||||
await browser.findElement(By.xpath('//form//button[contains(text(),"Add Key")]')).click();
|
|
||||||
|
|
||||||
await browser.wait(until.elementLocated(By.xpath('//p[contains(text(), "has been added.")]')), TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createRepo() {
|
|
||||||
await browser.get(`https://${app.fqdn}/repo/create`);
|
|
||||||
await browser.wait(until.elementLocated(By.id('repo_name')));
|
|
||||||
await browser.findElement(By.id('repo_name')).sendKeys(reponame);
|
|
||||||
var button = browser.findElement(By.xpath('//button[contains(text(), "Create Repository")]'));
|
|
||||||
await browser.executeScript('arguments[0].scrollIntoView(true)', button);
|
|
||||||
await browser.findElement(By.id('auto-init')).click();
|
|
||||||
await browser.findElement(By.xpath('//button[contains(text(), "Create Repository")]')).click();
|
|
||||||
|
|
||||||
await browser.wait(function () {
|
|
||||||
return browser.getCurrentUrl().then(function (url) {
|
|
||||||
return url === 'https://' + app.fqdn + '/' + username + '/' + reponame;
|
|
||||||
});
|
|
||||||
}, TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkCloneUrl() {
|
|
||||||
await browser.get('https://' + app.fqdn + '/' + username + '/' + reponame);
|
|
||||||
await browser.findElement(By.id('repo-clone-ssh')).click();
|
|
||||||
|
|
||||||
var cloneUrl = await browser.findElement(By.id('repo-clone-url')).getAttribute('value');
|
|
||||||
expect(cloneUrl).to.be(`ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame}.git`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cloneRepo() {
|
|
||||||
fs.rmSync(repodir, { recursive: true, force: true });
|
|
||||||
var env = Object.create(process.env);
|
var env = Object.create(process.env);
|
||||||
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
||||||
execSync(`git clone ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame}.git ${repodir}`, { env: env });
|
execSync(`git clone ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame}.git ${repodir}`, { env: env });
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushFile() {
|
function pushFile(done) {
|
||||||
const env = Object.create(process.env);
|
var env = Object.create(process.env);
|
||||||
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
env.GIT_SSH = __dirname + '/git_ssh_wrapper.sh';
|
||||||
execSync(`touch newfile && git add newfile && git commit -a -mx && git push ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame} main`,
|
execSync(`touch newfile && git add newfile && git commit -a -mx && git push ssh://git@${app.fqdn}:${SSH_PORT}/${username}/${reponame} master`,
|
||||||
{ env: env, cwd: repodir });
|
{ env: env, cwd: repodir });
|
||||||
fs.rmSync(repodir, { recursive: true, force: true });
|
rimraf.sync('/tmp/testrepo');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCustomFile(done) {
|
||||||
|
fs.writeFileSync('/tmp/customfile.txt', 'GOGS TEST', 'utf8');
|
||||||
|
execSync(`cloudron exec --app ${app.id} -- mkdir -p /app/data/custom/public`);
|
||||||
|
execSync(`cloudron push --app ${app.id} /tmp/customfile.txt /app/data/custom/public/customfile.txt`);
|
||||||
|
fs.unlinkSync('/tmp/customfile.txt');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCustomFile(done) {
|
||||||
|
superagent.get('https://' + app.fqdn + '/customfile.txt').end(function (error, result) {
|
||||||
|
if (error) return done(error);
|
||||||
|
|
||||||
|
expect(result.text).to.contain('GOGS TEST');
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fileExists() {
|
function fileExists() {
|
||||||
expect(fs.existsSync(repodir + '/newfile')).to.be(true);
|
expect(fs.existsSync(repodir + '/newfile')).to.be(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMail() {
|
function sendMail(done) {
|
||||||
await browser.get(`https://${app.fqdn}/admin/config`);
|
browser.get(`https://${app.fqdn}/admin/config`).then(function () {
|
||||||
|
var button = browser.findElement(by.xpath('//button[@id="test-mail-btn"]'));
|
||||||
var button = await browser.findElement(By.xpath('//button[contains(text(), "Send")]'));
|
return browser.executeScript('arguments[0].scrollIntoView(true)', button);
|
||||||
await browser.executeScript('arguments[0].scrollIntoView(true)', button);
|
}).then(function () {
|
||||||
await browser.findElement(By.xpath('//input[@name="email"]')).sendKeys('test@cloudron.io');
|
return browser.findElement(by.xpath('//input[@name="email"]')).sendKeys('test@cloudron.io');
|
||||||
await browser.findElement(By.xpath('//button[contains(text(), "Send")]')).click();
|
}).then(function () {
|
||||||
await browser.wait(until.elementLocated(By.xpath('//p[contains(text(), "A testing email has been sent")]')), TIMEOUT);
|
return browser.findElement(by.xpath('//button[@id="test-mail-btn"]')).click();
|
||||||
|
}).then(function () {
|
||||||
|
return browser.wait(until.elementLocated(by.xpath('//p[contains(text(),"A testing email has been sent to \'test@cloudron.io\'")]')), TIMEOUT);
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
xit('build app', function () { execSync('cloudron build', EXEC_ARGS); });
|
xit('build app', function () {
|
||||||
it('install app', function () { execSync(`cloudron install --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, EXEC_ARGS); });
|
execSync('cloudron build', { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can login', function (done) {
|
||||||
|
var inspect = JSON.parse(execSync('cloudron inspect'));
|
||||||
|
|
||||||
|
superagent.post(`https://${inspect.apiEndpoint}/api/v1/developer/login`).send({
|
||||||
|
username: username,
|
||||||
|
password: password
|
||||||
|
}).end(function (error, result) {
|
||||||
|
if (error) return done(error);
|
||||||
|
if (result.statusCode !== 200) return done(new Error('Login failed with status ' + result.statusCode));
|
||||||
|
|
||||||
|
token = result.body.accessToken;
|
||||||
|
|
||||||
|
superagent.get(`https://${inspect.apiEndpoint}/api/v1/profile`)
|
||||||
|
.query({ access_token: token }).end(function (error, result) {
|
||||||
|
if (error) return done(error);
|
||||||
|
if (result.statusCode !== 200) return done(new Error('Get profile failed with status ' + result.statusCode));
|
||||||
|
|
||||||
|
email = result.body.email;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('install app', function () {
|
||||||
|
execSync(`cloudron install --new --wait --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
});
|
||||||
|
|
||||||
it('can get app information', getAppInfo);
|
it('can get app information', getAppInfo);
|
||||||
|
it('can get the main page', function (done) {
|
||||||
|
superagent.get('https://' + app.fqdn).end(function (error, result) {
|
||||||
|
expect(error).to.be(null);
|
||||||
|
expect(result.status).to.eql(200);
|
||||||
|
|
||||||
it('can admin login', adminLogin);
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can login', login);
|
||||||
it('can send mail', sendMail);
|
it('can send mail', sendMail);
|
||||||
it('can logout', logout);
|
|
||||||
|
|
||||||
it('can login', loginOIDC.bind(null, username, password));
|
|
||||||
it('can set avatar', setAvatar);
|
it('can set avatar', setAvatar);
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
|
|
||||||
|
@ -232,60 +324,87 @@ describe('Application life cycle test', function () {
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
|
|
||||||
it('can add and push a file', pushFile);
|
it('can add and push a file', pushFile);
|
||||||
|
it('can edit file', editFile);
|
||||||
|
|
||||||
it('can restart app', function () { execSync('cloudron restart --app ' + app.id); });
|
it('can add custom file', addCustomFile);
|
||||||
|
it('can check custom file', checkCustomFile);
|
||||||
|
|
||||||
xit('can login', loginOIDC.bind(null, username, password)); // no need to relogin since session persists
|
it('can restart app', function (done) {
|
||||||
|
execSync('cloudron restart --wait --app ' + app.id);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can login', login);
|
||||||
it('displays correct clone url', checkCloneUrl);
|
it('displays correct clone url', checkCloneUrl);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in repo', fileExists);
|
it('file exists in repo', fileExists);
|
||||||
|
|
||||||
it('backup app', function () { execSync('cloudron backup create --app ' + app.id, EXEC_ARGS); });
|
it('backup app', function () {
|
||||||
it('restore app', function () { execSync('cloudron restore --app ' + app.id, EXEC_ARGS); });
|
execSync('cloudron backup create --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
});
|
||||||
|
|
||||||
it('can login', loginOIDC.bind(null, username, password));
|
it('restore app', function () {
|
||||||
|
execSync('cloudron restore --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can login', login);
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
||||||
|
|
||||||
it('move to different location', async function () {
|
it('move to different location', function (done) {
|
||||||
//browser.manage().deleteAllCookies(); // commented because of error "'Network.deleteCookie' wasn't found"
|
//browser.manage().deleteAllCookies(); // commented because of error "'Network.deleteCookie' wasn't found"
|
||||||
// ensure we don't hit NXDOMAIN in the mean time
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
await browser.get('about:blank');
|
browser.get('about:blank').then(function () {
|
||||||
|
execSync('cloudron configure --wait --location ' + LOCATION + '2 --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
var inspect = JSON.parse(execSync('cloudron inspect'));
|
||||||
|
app = inspect.apps.filter(function (a) { return a.location === LOCATION + '2'; })[0];
|
||||||
|
expect(app).to.be.an('object');
|
||||||
|
|
||||||
execSync('cloudron configure --location ' + LOCATION + '2 --app ' + app.id, EXEC_ARGS);
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('can get app information', getAppInfo);
|
|
||||||
|
|
||||||
it('can login', loginOIDC.bind(null, username, password));
|
it('can login', login);
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('displays correct clone url', checkCloneUrl);
|
it('displays correct clone url', checkCloneUrl);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
it('file exists in repo', function () { expect(fs.existsSync(repodir + '/newfile')).to.be(true); });
|
||||||
|
|
||||||
it('uninstall app', async function () {
|
it('uninstall app', function (done) {
|
||||||
// ensure we don't hit NXDOMAIN in the mean time
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
await browser.get('about:blank');
|
browser.get('about:blank').then(function () {
|
||||||
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
|
execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// No SSO
|
// check if the _first_ login via email succeeds
|
||||||
it('install app (no sso)', function () { execSync(`cloudron install --no-sso --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, EXEC_ARGS); });
|
it('can login via email', function (done) {
|
||||||
|
execSync(`cloudron install --new --wait --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
var inspect = JSON.parse(execSync('cloudron inspect'));
|
||||||
|
|
||||||
it('can get app information', getAppInfo);
|
app = inspect.apps.filter(function (a) { return a.location === LOCATION; })[0];
|
||||||
it('can admin login (no sso)', adminLogin);
|
expect(app).to.be.an('object');
|
||||||
it('can logout', logout);
|
|
||||||
|
|
||||||
it('uninstall app (no sso)', async function () {
|
login(function (error) {
|
||||||
await browser.get('about:blank');
|
if (error) return done(error);
|
||||||
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
|
|
||||||
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
|
browser.get('about:blank').then(function () {
|
||||||
|
execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// test update
|
// test update
|
||||||
it('can install app', function () { execSync(`cloudron install --appstore-id ${app.manifest.id} --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, EXEC_ARGS); });
|
it('can install app', function () {
|
||||||
|
execSync(`cloudron install --new --wait --appstore-id ${app.manifest.id} --location ${LOCATION} -p SSH_PORT=${SSH_PORT}`, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
});
|
||||||
|
|
||||||
it('can get app information', getAppInfo);
|
it('can get app information', getAppInfo);
|
||||||
it('can login', loginOIDC.bind(null, username, password));
|
it('can login', login);
|
||||||
it('can set avatar', setAvatar);
|
it('can set avatar', setAvatar);
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('can add public key', addPublicKey);
|
it('can add public key', addPublicKey);
|
||||||
|
@ -293,21 +412,21 @@ describe('Application life cycle test', function () {
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('can add and push a file', pushFile);
|
it('can add and push a file', pushFile);
|
||||||
|
|
||||||
it('can update', function () { execSync('cloudron update --app ' + app.id, EXEC_ARGS); });
|
it('can update', function () {
|
||||||
it('can get app information', getAppInfo);
|
execSync('cloudron install --wait --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
});
|
||||||
|
|
||||||
it('can admin login', adminLogin);
|
it('can login', login);
|
||||||
it('can send mail', sendMail);
|
it('can send mail', sendMail);
|
||||||
it('can logout', logout);
|
|
||||||
|
|
||||||
it('can login', loginOIDC.bind(null, username, password));
|
|
||||||
it('can get avatar', checkAvatar);
|
it('can get avatar', checkAvatar);
|
||||||
it('can clone the url', cloneRepo);
|
it('can clone the url', cloneRepo);
|
||||||
it('file exists in cloned repo', fileExists);
|
it('file exists in cloned repo', fileExists);
|
||||||
|
|
||||||
it('uninstall app', async function () {
|
it('uninstall app', function (done) {
|
||||||
// ensure we don't hit NXDOMAIN in the mean time
|
// ensure we don't hit NXDOMAIN in the mean time
|
||||||
await browser.get('about:blank');
|
browser.get('about:blank').then(function () {
|
||||||
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
|
execSync('cloudron uninstall --app ' + app.id, { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' });
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue