diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000000..91f2bc0273 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,71 @@ +name: Integration Tests + +on: + - pull_request + - push + +jobs: + e2e_tests: + runs-on: ubuntu-latest + steps: + - name: Get the branch name + id: get_branch + run: echo "branch=$(echo ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}})" >> $GITHUB_OUTPUT + + - name: Get the originating repository + id: get_repo + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "repo=${{ github.event.pull_request.head.repo.full_name }}" >> $GITHUB_OUTPUT + else + echo "repo=${{ github.repository }}" >> $GITHUB_OUTPUT + fi + + - name: Repository Dispatch + env: + TOKEN: ${{ secrets.PAT_INTEGRATION_TESTS }} + run: | + curl -X POST https://api.github.com/repos/expressjs/examples/dispatches \ + -H 'Accept: application/vnd.github.everest-preview+json' \ + -H "Authorization: token $TOKEN" \ + --data '{"event_type": "integration-tests", "client_payload": {"branch": "${{ steps.get_branch.outputs.branch }}", "repo": "${{ steps.get_repo.outputs.repo }}"}}' + + # Wait for the workflow to start + sleep 60 + + # Get the latest workflow run + response=$(curl -H "Authorization: token $TOKEN" https://api.github.com/repos/expressjs/examples/actions/runs) + workflow_url=$(echo "$response" | jq -r '.workflow_runs[0].url') + + status="" + start_time=$(date +%s) + timeout=$((10 * 60)) # timeout after 10 minutes + + while [[ "$status" != "completed" && $(( $(date +%s) - start_time )) -lt $timeout ]]; do + echo "checking..." + sleep 10 + response=$(curl -H "Authorization: token $TOKEN" $workflow_url) + status=$(echo "$response" | jq -r .status) + echo "current status: $status" + done + + if [[ $(( $(date +%s) - start_time )) -ge $timeout ]]; then + echo "Workflow did not complete within the expected time" + fi + + # Get the conclusion of the workflow run + conclusion=$(echo "$response" | jq -r .conclusion) + + # Get the URL of the workflow run + html_url=$(echo "$response" | jq -r .html_url) + echo "Check the workflow run for details: $html_url" + + if [[ "$status" == "completed" && "$conclusion" != "success" ]]; then + echo "Workflow completed but failed. Conclusion: $conclusion" + exit 1 + fi + + if [[ "$status" == "completed" && "$conclusion" == "success" ]]; then + echo "Workflow has been completed successfully" + exit 0 + fi \ No newline at end of file diff --git a/Readme.md b/Readme.md index d0f3cf56e6..824fffe7c1 100644 --- a/Readme.md +++ b/Readme.md @@ -101,19 +101,8 @@ $ npm start ## Examples - To view the examples, clone the Express repo and install the dependencies: + To view the examples, checkout [this dedicated repository](https://github.com/expressjs/examples) and follow the instructions in the README. -```console -$ git clone https://github.com/expressjs/express.git --depth 1 -$ cd express -$ npm install -``` - - Then run whichever example you want: - -```console -$ node examples/content-negotiation -``` ## Contributing diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index c19ed30a25..0000000000 --- a/examples/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Express examples - -This page contains list of examples using Express. - -- [auth](./auth) - Authentication with login and password -- [content-negotiation](./content-negotiation) - HTTP content negotiation -- [cookie-sessions](./cookie-sessions) - Working with cookie-based sessions -- [cookies](./cookies) - Working with cookies -- [downloads](./downloads) - Transferring files to client -- [ejs](./ejs) - Working with Embedded JavaScript templating (ejs) -- [error-pages](./error-pages) - Creating error pages -- [error](./error) - Working with error middleware -- [hello-world](./hello-world) - Simple request handler -- [markdown](./markdown) - Markdown as template engine -- [multi-router](./multi-router) - Working with multiple Express routers -- [multipart](./multipart) - Accepting multipart-encoded forms -- [mvc](./mvc) - MVC-style controllers -- [online](./online) - Tracking online user activity with `online` and `redis` packages -- [params](./params) - Working with route parameters -- [resource](./resource) - Multiple HTTP operations on the same resource -- [route-map](./route-map) - Organizing routes using a map -- [route-middleware](./route-middleware) - Working with route middleware -- [route-separation](./route-separation) - Organizing routes per each resource -- [search](./search) - Search API -- [session](./session) - User sessions -- [static-files](./static-files) - Serving static files -- [vhost](./vhost) - Working with virtual hosts -- [view-constructor](./view-constructor) - Rendering views dynamically -- [view-locals](./view-locals) - Saving data in request object between middleware calls -- [web-service](./web-service) - Simple API service diff --git a/examples/auth/index.js b/examples/auth/index.js deleted file mode 100644 index 36205d0f99..0000000000 --- a/examples/auth/index.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict' - -/** - * Module dependencies. - */ - -var express = require('../..'); -var hash = require('pbkdf2-password')() -var path = require('path'); -var session = require('express-session'); - -var app = module.exports = express(); - -// config - -app.set('view engine', 'ejs'); -app.set('views', path.join(__dirname, 'views')); - -// middleware - -app.use(express.urlencoded({ extended: false })) -app.use(session({ - resave: false, // don't save session if unmodified - saveUninitialized: false, // don't create session until something stored - secret: 'shhhh, very secret' -})); - -// Session-persisted message middleware - -app.use(function(req, res, next){ - var err = req.session.error; - var msg = req.session.success; - delete req.session.error; - delete req.session.success; - res.locals.message = ''; - if (err) res.locals.message = '
' + err + '
'; - if (msg) res.locals.message = '' + msg + '
'; - next(); -}); - -// dummy database - -var users = { - tj: { name: 'tj' } -}; - -// when you create a user, generate a salt -// and hash the password ('foobar' is the pass here) - -hash({ password: 'foobar' }, function (err, pass, salt, hash) { - if (err) throw err; - // store the salt & hash in the "db" - users.tj.salt = salt; - users.tj.hash = hash; -}); - - -// Authenticate using our plain-object database of doom! - -function authenticate(name, pass, fn) { - if (!module.parent) console.log('authenticating %s:%s', name, pass); - var user = users[name]; - // query the db for the given username - if (!user) return fn(null, null) - // apply the same algorithm to the POSTed password, applying - // the hash against the pass / salt, if there is a match we - // found the user - hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) { - if (err) return fn(err); - if (hash === user.hash) return fn(null, user) - fn(null, null) - }); -} - -function restrict(req, res, next) { - if (req.session.user) { - next(); - } else { - req.session.error = 'Access denied!'; - res.redirect('/login'); - } -} - -app.get('/', function(req, res){ - res.redirect('/login'); -}); - -app.get('/restricted', restrict, function(req, res){ - res.send('Wahoo! restricted area, click to logout'); -}); - -app.get('/logout', function(req, res){ - // destroy the user's session to log them out - // will be re-created next request - req.session.destroy(function(){ - res.redirect('/'); - }); -}); - -app.get('/login', function(req, res){ - res.render('login'); -}); - -app.post('/login', function (req, res, next) { - authenticate(req.body.username, req.body.password, function(err, user){ - if (err) return next(err) - if (user) { - // Regenerate session when signing in - // to prevent fixation - req.session.regenerate(function(){ - // Store the user's primary key - // in the session store to be retrieved, - // or in this case the entire user object - req.session.user = user; - req.session.success = 'Authenticated as ' + user.name - + ' click to logout. ' - + ' You may now access /restricted.'; - res.redirect('back'); - }); - } else { - req.session.error = 'Authentication failed, please check your ' - + ' username and password.' - + ' (use "tj" and "foobar")'; - res.redirect('/login'); - } - }); -}); - -/* istanbul ignore next */ -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} diff --git a/examples/auth/views/foot.ejs b/examples/auth/views/foot.ejs deleted file mode 100644 index b605728ee2..0000000000 --- a/examples/auth/views/foot.ejs +++ /dev/null @@ -1,2 +0,0 @@ -